Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Angular JS Design Patterns

Recommended coding patterns for medium to large sized Angular.js apps
by

Alan Biggs

on 20 April 2015

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Angular JS Design Patterns


.factory('InvoiceFactory', ['$http',
function($http)
{
return {
getAll: function(token) {
return $http.get(
'/docp/api-anon/internal/v0/invoices');
}
};
}])
What is Angular
really
?
MVC, MVVM, MVP? -
MV
W
-
Model-View-
Whatever!
Browsers were made for presenting static pages
Today that's only one application of them
We want dynamic applications.
If browsers were designed for building apps,
how would they be different?
That's the design goal behind Angular
Custom directives
augment
and
redefine
HTML tags
Any application can define its own 'vocabulary' and 'behaviours'



Forget what you already know and let's dive in!
Where does Angular fit in?
Behind the UI
On the client
In front of the web service

Works well with
Bootstrap
,
LESS
,
CSS
Deprecates
jQuery
,
DoJo
Parallels
Backbone
and
Ember
Competes with
Facebook React
Works well with
REST
services &
JSON
data
Makes DOM manipulation obsolete*
Hiding in Closures (IIFE)
IIFE = Immediate Inline Function Expression
Wrap all your js files in an IIFE
'use strict';

(function(){
'use strict';
var notGlobalNow;
var nowHidden = {};
function cantSeeMeAnyMore() {};

...component code...

}
()
);

// <--Run me when file loads
Modules, Routes, Views, Controllers, Scope, Services and Directives
Where's the model?
Data retrieved via services facade (Factory)
Placed into $scope by controller
Overview
What is Angular
really
?
Where does Angular fit in?
Modules, Routes, Views, Controllers, Scope, Services, and Directives
Project Organization
Hiding in Closures
The Problem with Anonymous Functions
Slim controllers
Control scope
Service API Patterns
Return a Promise
Use of Watches and Filters

* Unless you decide to write your own Directives

Like ADP did with ngRevit

(But that's a whole other session...)
Angular JS Design Patterns
The Problem with Anonymous Functions
When errors occur, hard to identify where

Example:

.factory('invoiceFactory', ['$http',
invoiceFactory
])

...

function
invoiceFactory
($http) {
return {
getAll: function(token) {
return $http.get(
'/docp/api-anon/internal/v0/invoices'
);
}
}
};
Slim Controllers
Think of the Controller as a conductor
Delegates everything it can to
services
Puts data objects into
scope
Changes to data in scope trigger UI updates in the
view
UI is managed with
directives
Formatting of data for presentation is done with
filters
and
formatters
Navigation is configured using
ngRoute
Note that controller is removed when navigating away from the view

Control scope
$scope contains the data that is placed in the view, set in controller
Angular best practice is moving away from putting everything directly into $scope
$scope hierarchies can be created
Can lead to conflicts, and weird behaviour
Use "controller as" syntax
Or "controllerAs" in controller definition
Service API Patterns
Typically a service provides data to the model
For us, typically an encapsulation to a REST resource from Controller
Basically a singleton object
3 Flavours
Factory
- Instantiated with new
Service
- returns itself
Provider
- Can be set up in config
Return a
promise

Return a Promise
Avoid callback hell!
Asyncronous pattern with success & failure handlers
Promise design pattern:
"I promise I'll get back to you and let you know the result"
then you can process the result
success - I got the result (good or bad)
error - I couldn't get the result
$q
- implementation of promise API
$http
returns a promise plus two convenience methods:
.success
and
.error
$resource
returns an object class and also a
$promise
object
What to Watch
Angular watches the scope for changes
When change detected view updated
Can get sluggish - be pragmatic

More about that next time...
angular.module('customersApp')

.factory
('dataFactory', ['$http', function($http)
{
var urlBase = '/api/customers';

var FactoryObject = {};


FactoryObject.
getAllCustomers = function () {
return $http.get(urlBase);
};


FactoryObject.
getCustomer = function (id) {
return $http.get(urlBase + '/' + id);
};


FactoryObject.
insertCustomer = function (cust) {
return $http.post(urlBase, cust);
};


return FactoryObject;
}]);
Factory
angular.module('customersApp')

.service
('dataService', ['$http', function($http) {
var urlBase = '/api/customers';
//var dataFactory = {};
//No object to create
//Add functions to this

this.
getAllCustomers = function () {
return $http.get(urlBase);
};


this.
getCustomer = function (id) {
return $http.get(urlBase + '/' + id);
};


this.
insertCustomer = function (cust) {
return $http.post(urlBase, cust);
};

//'this' will be returned
//return dataFactory;
}]);
SERVICE
angular.module('customersApp')

.controller
('customersController', ['$scope', 'dataFactory',
function ($scope, dataFactory) {

function getCustomers() {

dataFactory.getCustomers()

.success
(function (custs) {

$scope.customers = custs;
})

.error
(function (error) {

$scope.status = 'Unable to load customer data: ' + error.message;
});
}

//Run it on instantiation

getCustomers();
...
$HTTP RESPONse example
angular.module('customersApp')

.controller
('customersController', ['$scope', 'dataFactory',
function ($scope, dataFactory) {

function getCustomers() {

dataFactory.getCustomers().
then(
function(custs) {
//success handler

$scope.customers = custs;
},
function (error) {
//error handler

$scope.status = 'Unable to load customer data: ' + error.message;
}

//Note: promises can also have progress handler
);
}

//Run it on instantiation

getCustomers();
...
promise example using then
(function() {
//IIFE

'use strict';


angular
.module('myApp')
.service('MyService', [
'$http',
'APIConst',

MyService
]);


function MyService
($http, APIConst) {
var urlBase = APIConst.apiBaseUrl + '/customers';

this.
getAllCustomers = function () {
return $http.get(urlBase);
//returns a promise


};
};

}());
SERVICE with all the plumbing
In customersApp.js:

angular

.module
(

'customersApp'
, []) //<-- Must define dependency array

.config
(...)

.constant
(...)

.value
(...)

.controller(...)

.service
(...)

.factory
(...); //etc
Define a Module
In MyService.js:

angular

.module
(

'customersApp'
) //<-- No deps? - assume module exists

.service
('MyService',
['$http',
function($http){...} //<-- Service Implementation
]);
Filters
Instead of bloating up services and controllers with presentation logic use filters
Format the value before presentation
Built-in
Currency
Date/Time
etc.
Build your own
timeConversionFilter
booleanCheckmarkFilter

Stay tuned...
In HTML:

<div ng-controller="
MyController as my
">
<input ng-model="
my.
someValue">
<div ng-repeat="number in
my.
list">
<input ng-model="
my.
someValue">
</div>
</div>
"Controller as" view model
In controller code:

// better
function MyController () {
//'controller as' enables use of 'this' instead of $scope

this.
doSomething = function () {...};

//But context of 'this' might change in the function!
}

// recommended
function MyController (myService) {

var vm = this;

//vm: ViewModel
vm.doSomething = myService.doSomething();
}
Angular - The Good Parts
JavaScript is a dynamic language
Many ways to make things 'work'
Is there a best way?
Reticent to say best - some ways are better

Recommendations
(
not
standards!)
Todd Motto Coding Styleguide
https://github.com/toddmotto/angularjs-styleguide
John Papa Coding Styleguide
https://github.com/johnpapa/angularjs-styleguide
(Papa don't preach...)
Project organization
Prefer functional organization (
folders-by-feature
) over component organization (
folders-by-type
)
One file per component
Choose a file naming convention & stick to it
Easier to move files around into new folders than to rename files
Create module once in module definition file
Then get it and append to it in each component file

NOTE:
Remember to update dependencies when including new components in index.html
PROJECT STRUCTURE
Implementation patterns
In MyService.js:

angular

.module
(
'myApp'
)
//Get the module

.service
('MyService', MyService);

function MyService(){...}
In MyController.js:

angular

.module
(
'myApp'
)
//Get the module

.controller
('MyController', MyController);

function MyController(){...}
//<-- Note the syntax used here
In myApp.js:

angular

.module
(
'myApp', [
//Create module myApp
'ngRoute',
'app.dependency']
)
"Create watches with caution as they add more load to the digest cycle."
John Papa
Next Up


Data binding in the view
App Initialization
Angular UI Router
Templates, Filters, Formatters and Parsers
Event handling
Extending with Directives
ngRevit and beyond
Event handling
User feedback
Validation & Animation
Implementing Styles
ADVANCED

app/
app.module.js
app.config.js
app.routes.js
components/
calendar.directive.js
calendar.directive.html
user-profile.directive.js
user-profile.directive.html
layout/
shell.html
shell.controller.js
topnav.html
topnav.controller.js
people/
attendees.html
attendees.controller.js
speakers.html
speakers.controller.js
services/
data.service.js
localstorage.service.js
sessions/
sessions.html
sessions.controller.js
EARLY

app/
app.js
feed/
feed.html
FeedController.js FeedEntryDirective.js FeedService.js
Login/
_login.html
LoginController.js
LoginService.js
Shared/
CapitalizeFilter.js

function SomeController($scope, $log) {
var vm = this;
vm.title = 'Some Title';


$scope.$watch
('vm.title',
function(current, original) {
$log.info('vm.title was %s', original);
$log.info('vm.title is now %s', current);
});
}
WATCHER EXAMPLE
But success and error are convenience functions
Not actually part of the promise API
Angular JS View Patterns
"When you get overly attached to MVC, then you look at every class you create and ask the question “is this a model, a view, or a controller?”. Because this question makes no sense, the answer doesn’t either: anything that isn’t evidently data or evidently graphics gets put into the amorphous “controller” collection, which eventually sucks your entire codebase into its innards like a black hole collapsing under its own weight."

Graham Lee
"AngularJS lets you extend HTML vocabulary for your application."
angularjs.org
Full transcript