Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Cleaner Opinionated AngularJS
Prabhakar Doraisamy	

August 2014
var app = angular.module('app', []);	

app.controller('MyCtrl', function () {

…

});
function MainCtrl () {

	

 …

}	

angular

.module('app', [])

.controller('MainCtrl', MainCtrl);
Better
(function () {

	

 angular.module('app', []);	

	

 function MainCtrl () {

	

 }



	

 angular

	

 .module('app')

	

 .controller('MainCtrl', MainCtrl);

})();
BestDefining a module
• aids in stack traces as functions aren't anonymous • avoids polluting the global namespace
Better
Better #2Dependency injection
• Using the array syntax to declare dependencies works with minification
function MainCtrl(anyVariableName, $q) {	

}

MainCtrl.$inject = ['$http',‘$q’];	

angular

.module('app', [])

.controller('MainCtrl', MainCtrl);
var app = angular.module('app', []);	

app.controller('MainCtrl', [ '$http', '$q', function($http, $q){

…

});
var app = angular.module('app', []);	

app.controller('MainCtrl', function ($http, $q) {

…

});
<div ng-controller="MainCtrl">	

{{ someObject }}	

</div>
<div ng-controller="MainCtrl as main">	

{{ main.someObject }}	

</div>
Better
<div>

{{ main.someObject }}

</div>	

!
function config ($routeProvider) {

$routeProvider

.when('/', {

templateUrl: 'views/main.html',

controller: 'MainCtrl',

controllerAs: 'main'

});

}	

angular

.module('app')

.config(config);
BestAdding controller to a view
• Controllers are classes	

• aids in nested scoping and controller instance reference.
• avoids tight coupling ie., reusable view with different controllers	

• avoids using $parent to access any parent controllers from a child controller
function MainCtrl ($scope) {

$scope.someObject = {};

$scope.doSomething = function () {

};

}	

angular

.module('app')

.controller('MainCtrl', MainCtrl);
function MainCtrl ($scope) {

this.someObject = {};

this._$scope = $scope;

}	

MainCtrl.prototype.doSomething = function () {

// use this._$scope

};	

angular

.module('app')

.controller('MainCtrl', MainCtrl);
Slightly better
function MainCtrl () {

this.someObject = {};

this.doSomething = function () {

};

}	

angular

.module('app')

.controller('MainCtrl', MainCtrl);	

function config ($routeProvider) {

$routeProvider

.when('/', {

templateUrl: 'views/main.html',

controller: 'MainCtrl',

controllerAs: 'main'

});

}
Betterthis and $scope
• Good for inheritance	

• controllerAs syntax uses this keyword inside controllers instead of $scope. 	

• When using controllerAs, the controller is infact bound to $scope, but there is a degree of separation.
function SomeService () {

}	

angular

.module('app')

.factory('$$SomeService', SomeService);
• $ incites they’re public and can be used.	

• $scope and $rootScope	

• $$ are considered private methods.	

• $$listeners, which are available on the Object	

function SomeService () {

}	

angular

.module('app')

.factory('SomeService', SomeService);
Better
• Avoid using two different names for the Service definition, and the function name for consistency
and stack tracing.
Naming services/directives/providers/factories
<input ng-model=“myModel">	

function MainCtrl(){

$scope.$watch('myModel', function () {

// go

});

}
<input ng-model="myModel" ng-change="callback">	

function MainCtrl(){

$scope.callback = function () {

// go

};

} 	

Better
• Avoid $scope.$watch unless there are no others options	

• less performant than binding an expression to something like ng-change
Watching data change
function MainCtrl () {

this.doSomething = function () {

};

}	

angular

.module('app')

.controller('MainCtrl', MainCtrl);
function MainCtrl (SomeService) {

this.doSomething = SomeService.doSomething;

}	

angular

.module('app')

.controller('MainCtrl', MainCtrl);
Better
• delegating logic to Factories/Services	

• maximises reusability
Controller logic
function AnotherService () {

var someValue = '';

var someMethod = function () {

};	

return {

someValue: someValue,

someMethod: someMethod

};

}	

angular

.module('app')

.factory('AnotherService',AnotherService);
function AnotherService () {

var AnotherService = {};

AnotherService.someValue = ‘’;

AnotherService.someMethod = function () {

};	

return AnotherService;

}	

angular

.module('app')

.factory('AnotherService',AnotherService);
Better
• makes internal module namespacing a little easier	

• easy to read any private methods and variables
Factory
function MainCtrl (SomeService) {

this.makeActive = function (elem) {

$(elem).addClass(‘test’);

};

}	

angular

.module('app')

.controller('MainCtrl', MainCtrl);	

function SomeDirective (SomeService) {

return {

restrict: 'EA',

template: [

'<a href="" class="myawesomebutton" ng-transclude>',

'<i class="icon-ok-sign"></i>',

'</a>'

].join(''),	

link: function ($scope, $element, $attrs) {

// DOM manipulation/events here!

$element.on('click', function () {

$(this).addClass('test');

});

}

};

}	

angular

.module('app')

.directive('SomeDirective', SomeDirective);
Better
• Any DOM manipulation should take place inside a directive, and only directives
DOM manipulation
If you are writing $(element) somewhere in your
controller, its a indication that you need a directive.
function ngFocus (SomeService) {

return {};

}	

angular

.module('app')

.directive('ngFocus', ngFocus);
function focusFire (SomeService) {

return {};

}	

angular

.module('app')

.directive('focusFire', focusFire);
Better
• Custom directives should not be ng-* prefixed to prevent future core overrides
Naming a directive
<!-- directive: my-directive -->	

<div class="my-directive"></div>
Followed by adding restrict usage using the restrict property inside each directive's Object. 	

• E for element	

• A for attribute	

• M for comment (avoid)	

• C for className (avoid this too as it's even more confusing, but plays better with IE).	

• Multiple restrictions, such as restrict: 'EA'.
BetterDirective usage restriction
<my-directive></my-directive>	

<div my-directive></div>
function MainCtrl (SomeService) {

var self = this; // unresolved

self.something;

// resolved asynchronously 

SomeService.doSomething().then(function (response) {

self.something = response;

});

}	

angular

.module('app')

.controller('MainCtrl', MainCtrl);
function config ($routeProvider) {

$routeProvider

.when('/', {

templateUrl: 'views/main.html',

resolve: {

doSomething: function (SomeService) {

return SomeService.doSomething();

}

}

});

}

function MainCtrl (SomeService) {

// resolved!

this.something = SomeService.something;

}

angular..module(‘app').controller('MainCtrl', MainCtrl);

angular.module(‘app').config(config);
Better
// config with resolve pointing to relevant controller

function config ($routeProvider) {

$routeProvider

.when('/', {

templateUrl: 'views/main.html',

controller: 'MainCtrl',

controllerAs: 'main',

resolve: MainCtrl.resolve

});

}	

// controller as usual

function MainCtrl (SomeService) {

// resolved!

this.something = SomeService.something;

}	

// create the resolved property

MainCtrl.resolve = {

doSomething: function (SomeService) {

return SomeService.doSomething();

}

};	

angular

.module(‘app')

.controller('MainCtrl', MainCtrl)

.config(config);
BestInit data for a view
• keeping router tidy	

• progress. indicator using the $routeChangeStart event
• keeping controller tidy

More Related Content

Opinionated AngularJS

  • 2. var app = angular.module('app', []); app.controller('MyCtrl', function () {
 …
 }); function MainCtrl () {
 …
 } angular
 .module('app', [])
 .controller('MainCtrl', MainCtrl); Better (function () {
 angular.module('app', []); function MainCtrl () {
 }
 
 angular
 .module('app')
 .controller('MainCtrl', MainCtrl);
 })(); BestDefining a module • aids in stack traces as functions aren't anonymous • avoids polluting the global namespace
  • 3. Better Better #2Dependency injection • Using the array syntax to declare dependencies works with minification function MainCtrl(anyVariableName, $q) { }
 MainCtrl.$inject = ['$http',‘$q’]; angular
 .module('app', [])
 .controller('MainCtrl', MainCtrl); var app = angular.module('app', []); app.controller('MainCtrl', [ '$http', '$q', function($http, $q){
 …
 }); var app = angular.module('app', []); app.controller('MainCtrl', function ($http, $q) {
 …
 });
  • 4. <div ng-controller="MainCtrl"> {{ someObject }} </div> <div ng-controller="MainCtrl as main"> {{ main.someObject }} </div> Better <div>
 {{ main.someObject }}
 </div> ! function config ($routeProvider) {
 $routeProvider
 .when('/', {
 templateUrl: 'views/main.html',
 controller: 'MainCtrl',
 controllerAs: 'main'
 });
 } angular
 .module('app')
 .config(config); BestAdding controller to a view • Controllers are classes • aids in nested scoping and controller instance reference. • avoids tight coupling ie., reusable view with different controllers • avoids using $parent to access any parent controllers from a child controller
  • 5. function MainCtrl ($scope) {
 $scope.someObject = {};
 $scope.doSomething = function () {
 };
 } angular
 .module('app')
 .controller('MainCtrl', MainCtrl); function MainCtrl ($scope) {
 this.someObject = {};
 this._$scope = $scope;
 } MainCtrl.prototype.doSomething = function () {
 // use this._$scope
 }; angular
 .module('app')
 .controller('MainCtrl', MainCtrl); Slightly better function MainCtrl () {
 this.someObject = {};
 this.doSomething = function () {
 };
 } angular
 .module('app')
 .controller('MainCtrl', MainCtrl); function config ($routeProvider) {
 $routeProvider
 .when('/', {
 templateUrl: 'views/main.html',
 controller: 'MainCtrl',
 controllerAs: 'main'
 });
 } Betterthis and $scope • Good for inheritance • controllerAs syntax uses this keyword inside controllers instead of $scope. • When using controllerAs, the controller is infact bound to $scope, but there is a degree of separation.
  • 6. function SomeService () {
 } angular
 .module('app')
 .factory('$$SomeService', SomeService); • $ incites they’re public and can be used. • $scope and $rootScope • $$ are considered private methods. • $$listeners, which are available on the Object function SomeService () {
 } angular
 .module('app')
 .factory('SomeService', SomeService); Better • Avoid using two different names for the Service definition, and the function name for consistency and stack tracing. Naming services/directives/providers/factories
  • 7. <input ng-model=“myModel"> function MainCtrl(){
 $scope.$watch('myModel', function () {
 // go
 });
 } <input ng-model="myModel" ng-change="callback"> function MainCtrl(){
 $scope.callback = function () {
 // go
 };
 } Better • Avoid $scope.$watch unless there are no others options • less performant than binding an expression to something like ng-change Watching data change
  • 8. function MainCtrl () {
 this.doSomething = function () {
 };
 } angular
 .module('app')
 .controller('MainCtrl', MainCtrl); function MainCtrl (SomeService) {
 this.doSomething = SomeService.doSomething;
 } angular
 .module('app')
 .controller('MainCtrl', MainCtrl); Better • delegating logic to Factories/Services • maximises reusability Controller logic
  • 9. function AnotherService () {
 var someValue = '';
 var someMethod = function () {
 }; return {
 someValue: someValue,
 someMethod: someMethod
 };
 } angular
 .module('app')
 .factory('AnotherService',AnotherService); function AnotherService () {
 var AnotherService = {};
 AnotherService.someValue = ‘’;
 AnotherService.someMethod = function () {
 }; return AnotherService;
 } angular
 .module('app')
 .factory('AnotherService',AnotherService); Better • makes internal module namespacing a little easier • easy to read any private methods and variables Factory
  • 10. function MainCtrl (SomeService) {
 this.makeActive = function (elem) {
 $(elem).addClass(‘test’);
 };
 } angular
 .module('app')
 .controller('MainCtrl', MainCtrl); function SomeDirective (SomeService) {
 return {
 restrict: 'EA',
 template: [
 '<a href="" class="myawesomebutton" ng-transclude>',
 '<i class="icon-ok-sign"></i>',
 '</a>'
 ].join(''), link: function ($scope, $element, $attrs) {
 // DOM manipulation/events here!
 $element.on('click', function () {
 $(this).addClass('test');
 });
 }
 };
 } angular
 .module('app')
 .directive('SomeDirective', SomeDirective); Better • Any DOM manipulation should take place inside a directive, and only directives DOM manipulation
  • 11. If you are writing $(element) somewhere in your controller, its a indication that you need a directive.
  • 12. function ngFocus (SomeService) {
 return {};
 } angular
 .module('app')
 .directive('ngFocus', ngFocus); function focusFire (SomeService) {
 return {};
 } angular
 .module('app')
 .directive('focusFire', focusFire); Better • Custom directives should not be ng-* prefixed to prevent future core overrides Naming a directive
  • 13. <!-- directive: my-directive --> <div class="my-directive"></div> Followed by adding restrict usage using the restrict property inside each directive's Object. • E for element • A for attribute • M for comment (avoid) • C for className (avoid this too as it's even more confusing, but plays better with IE). • Multiple restrictions, such as restrict: 'EA'. BetterDirective usage restriction <my-directive></my-directive> <div my-directive></div>
  • 14. function MainCtrl (SomeService) {
 var self = this; // unresolved
 self.something;
 // resolved asynchronously 
 SomeService.doSomething().then(function (response) {
 self.something = response;
 });
 } angular
 .module('app')
 .controller('MainCtrl', MainCtrl); function config ($routeProvider) {
 $routeProvider
 .when('/', {
 templateUrl: 'views/main.html',
 resolve: {
 doSomething: function (SomeService) {
 return SomeService.doSomething();
 }
 }
 });
 }
 function MainCtrl (SomeService) {
 // resolved!
 this.something = SomeService.something;
 }
 angular..module(‘app').controller('MainCtrl', MainCtrl);
 angular.module(‘app').config(config); Better // config with resolve pointing to relevant controller
 function config ($routeProvider) {
 $routeProvider
 .when('/', {
 templateUrl: 'views/main.html',
 controller: 'MainCtrl',
 controllerAs: 'main',
 resolve: MainCtrl.resolve
 });
 } // controller as usual
 function MainCtrl (SomeService) {
 // resolved!
 this.something = SomeService.something;
 } // create the resolved property
 MainCtrl.resolve = {
 doSomething: function (SomeService) {
 return SomeService.doSomething();
 }
 }; angular
 .module(‘app')
 .controller('MainCtrl', MainCtrl)
 .config(config); BestInit data for a view • keeping router tidy • progress. indicator using the $routeChangeStart event • keeping controller tidy