Yaniv Efraim
I am a senior Front End developer @Supersonic
Developing for the web for more than 10 years
Love Javascript
Live slides: http://tinyurl.com/angularil-realworld
app/
app.module.js
app.config.js
controllers/
attendees.js
session-detail.js
...
directives/
calendar.directive.js
calendar.directive.html
...
services/
dataservice.js
localstorage.js
...
views/
attendees.html
session-detail.html
sessions.html
...
app/
----- components/ //reusable components
---------- sidebar/
--------------- sidebar.module.js
--------------- sidebarDirective.js
--------------- sidebarView.html
--------------- _sidebar.scss
--------------- sidebar_test.js
---------- article/
--------------- article.module.js
--------------- articleDirective.js
--------------- articleView.html
--------------- ...
----- pages/ // acts as pages or partials of our site
---------- home/
--------------- home.module.js
--------------- homeController.js
--------------- homeService.js
--------------- homeView.html
--------------- _home.scss
--------------- home_test.js
----- app.module.js
----- app.routes.js
index.html
Each component should have its own module:
---------- home/
--------------- home.module.js
--------------- home.controller.js
--------------- home.service.js
--------------- home.view.html
--------------- home.css
--------------- home_test.js
angular.module('home',[]);//home.module.js
angular.module('home').controller('HomeCtrl', HomeCtrl);//home.controller.js
angular.module('home').factory('homeService', homeService);//home.service.js
Root module should be a container referencing all depending modules:
angular.module('app',[
//Angular Modules
'ngRoute',
//Custom modules
'sidebar',
'article',
'home',
'blog',
//3rd Party Modules
'ui.bootstrap'
]);
Further reading:
Using ControllerAs syntax, we are creating an instance:
<div ng-controller="MainCtrl as main">
{{ main.title }}
</div>
angular.module('myApp', [])
.controller("MainCtrl", MainCtrl);
function MainCtrl() {
this.title = "My Title";
this.sendMessage = function() { };
}
Or even better:
<div ng-controller="MainCtrl as main">
{{ main.title }}
</div>
angular.module('myApp', [])
.controller("MainCtrl", MainCtrl);
function MainCtrl() {
var vm = this;// vm stands for 'viewmodel'
vm.title = "My Title";
vm.sendMessage = function() { };
}
How ControllerAs is implemented behind the scenes
ControllerAs - Nested controllers (the "dot rule")
(Problem)
(Solution)
Syntax is closer to that of a "vanilla" JavaScript constructor
Avoid using controllers. Use directives instead:
Further reading:
(don't use it as a model)
angular.module('Store', [])
.controller('OrderCtrl', function(Products) {
this.products = Products.query();
this.items = [];
this.addToOrder = function(item) {
this.items.push(item);
};
this.removeFromOrder = function(item) {
this.items.splice(this.items.indexOf(item), 1);//-->Business logic inside controller
};
this.totalPrice = function() {
return this.items.reduce(function(memo, item) {
return memo + (item.qty * item.price);//-->Business logic inside controller
}, 0);
};
});
angular.module('Store')
.factory('Order', function() {
var add = function(item) {
this.items.push(item);
};
var remove = function(item) {
if (this.items.indexOf(item) > -1) {
this.items.splice(this.items.indexOf(item), 1);
}
};
var total = function() {
return this.items.reduce(function(memo, item) {
return memo + (item.qty * item.price);
}, 0);
};
return {
items: [],
addToOrder: add,
removeFromOrder: remove,
totalPrice: total
};
});
angular.module('Store', [])
.controller('OrderCtrl', function(Products, Order) {
this.products = Products.query();
this.items = Order.items;
this.addToOrder = function(item) {
Order.addToOrder(item);
};
this.removeFromOrder = function(item) {
Order.removeFromOrder(item);
};
this.totalPrice = function() {
return Order.total();
};
});
Further reading:
var app = angular
.module('app')
.controller('HomeController', HomeController);
function HomeController(){
var vm = this;
vm.name = 'my name';
};
(How many globals do you see here?)
(function(){
var app = angular
.module('app')
.controller('HomeController', HomeController);
function HomeController(){
var vm = this;
vm.name = 'my name';
};
})();
For AngularJS > 1.3 use "one-time binding"
Use "bindonce.js" for AngularJS <= 1.2 (https://github.com/Pasvaz/bindonce)
One-time expressions will stop recalculating once
they are stable, which happens after the first digest…
<p>Hello {{name}}!</p>
Becomes:
<p>Hello {{::name}}!</p>
Anguler 1.3+ :
Anguler <= 1.2 :
app.controller('MyController',
['serviceA', 'serviceB', function(serviceA, serviceB){
...
}])
Will become:
app.controller('MyController', myController);
function myController(serviceA, serviceB){
...
}
ng-annotate will automatically add:
myController.$inject = ["serviceA", "serviceB"];
The usual controller decleration:
For complex scenarios explicitly use the @ngInject
app.controller('MyController', myController);
function myController(){
...
}
/* @ngInject */
myController.prototype.methodA = function(serviceA, serviceB){
...
}
ng-annotate will recognise the need for injection and add:
myController.prototype.methodA.$inject = ["serviceA", "serviceB"];
html2js output file example (auto-generated by html2js task):
angular.module("compiled-templates", []).run(["$templateCache", function($templateCache) {
$templateCache.put("all-templates",
"<script type=text/ng-template id=my-directive-template.html><div ng-controller=\"SomeCtrl\" class=\"some-class\" ng-click=\"performeClick()\">\n" +
" <div class=\"div-class\">\n" +
" ...
" </div>\n" +
" </div></script>);
});
Templates module should be added to main module:
angular.module('myApp', [ 'compiled-templates', /* other dependencies */ ]);
Compile generated templates in your main controller:
var templatesHTML = $templateCache.get('all-templates');
$compile(templatesHTML)($rootScope);
Reference your templates as usual:
myApp.directive("myDirective", [function () {
return{
scope:{},
restrict: 'E',
templateUrl: 'my-directive-template.html',
link: function(scope, element, attrs){
},
controller: ['$scope', function($scope){
}]
};
}]);
Further reading:
app.config(function($routeProvider) {
var getName = function(NameService) {
return NameService.getName();
};
$routeProvider
.when('/profile', {
templateUrl: '/profile.html',
controller: 'ProfileController',
/* only navigate when we've resolved these promises */
resolve: {
name: getName,
profile: getProfile,
anythingElse: getAnythingElse
}
})
});
var dataPromise = null;
function getData() {
if (dataPromise == null)
dataPromise = $http.get("data.json").then(function (res) {
return res.data;
});
return dataPromise;
}
Use Component-Based Architecture (a.k.a. use directives, not ng-controllers)
Reduce dependency on $scope
Be modular
Use AngularUI's ui-router
Don't use angular.element
Further reading: