This
resource contains a collection of AngularJS best practices and AngularJS tips
provided by our Toptal network members. As such, this page will be updated on a
regular basis to include additional information and cover emerging AngularJS
techniques. This is a community driven project, so you are encouraged to
contribute as well, and we are counting on your feedback.
Unlike
some other JavaScript frameworks, AngularJS requires the developer to do things
the “Angular” way, which is a set of rules and best practices that are critical
to building AngularJS web applications properly. Here we will embrace those
best practices that will make you a better AngularJS developer.
Check out
the Toptal resource pages for additional information on AngularJS common mistakes, AngularJSjob description and AngularJS interview questions.
How to Use
`controllerAs` Syntax properly?
Angular
is a very powerful framework, sometimes too powerful causing some developers to
make some architecture mistakes. The two-way data binding and the power of
directives are awesome, but you need to think about what are you doing and try
to use some best practices to avoid common pitfalls during the development
process.
Controllers are class-like objects to “control” the
model and update the view, and as you know everything is based around the magic
and mystic $scope property.
A good practice is to avoid binding everything to $scope, because too many bindings crowd
the watch list of the $digest loop.
To avoid that, Angular give us the controllerAs property.
Writing controllers as classes
A class
in Javascript (at least in ES5 for now) is something like this:
var aClass = function () {
this.name = 'Class name';
};
var instance = new aClass();
With this you can use the instance variable to access methods
and properties.
Using the controllerAs property
we write our Controllers in the same way, using this instead of $scope
angular.module('myApp')
.controller('MyCtrl', function
() {
this.name = 'Controller Name';
});
Now this
can be instantiated in the template with something like the following:
<div
ng-controller="MyCtrl as vm">
<h1 ng-bind="vm.name"></h1>
</div>
To access the properties and methods of the
controller you use the vm instance.
With this
you are namespacing the scopes, making the code cleaner and readable. Think
about nested scopes.
<div
ng-controller="BaseCtrl">
{{ name }}
<div ng-controller="SectionCtrl">
{{ name }}
<div
ng-controller="FinalCtrl">
{{ name }}
</div>
</div>
</div>
Here you can see that each controller is accessing
the name property, but the question
is: which one? That code looks very confusing and is probably that one
controller takes precedence over another, but you don’t know which one.
Using the controllerAs syntax
this will be much cleaner:
<div
ng-controller="BaseCtrl as base">
Base scope: {{ base.name }}
<div ng-controller="SectionCtrl as section">
Section scope: {{ section.name }}
Base scope: {{base.name}}
<div ng-controller="FinalCtrl as final">
{{ final.name }}
</div>
</div>
</div>
As we can see in the above code, using controllerAs syntax allows us access to
parent scopes without the hassle of scope collision and without using $parent to access it.
How to set watchers
One question that comes to mind when you use this
kind of syntax is how to use a $watch call
because you need to inject $scope. We
fight to remove the use of $scope, and now
we need to inject it anyway.
Well, we can keep using controllerAs and keep binding methods and
properties to the this object
that is binded to the current $scope. At the
same time, we can keep the separation of concerns using $scope only for special cases,
like $watch, $on, or $broadcast.
Keep in mind that using controllerAs the syntax for $watch method changes a little
bit. Normally you would do something like the following:
app.controller('Ctrl', function
($scope) {
$scope.name = 'name';
$scope.$watch('name', function (oldVal,
newVal) {
});
});
But that doesn’t work now, because $watch is looking for the watched
property inside the $scope, and you
don’t directly bind that property to $scope. Instead
watched property is binded to this. The
correct way to do it now is as shown in the following example:
app.controller('Ctrl', function
($scope) {
this.name = 'name';
$scope.$watch(function () {
return this.title
}.bind(this), function (oldVal, newVal) {
});
});
Alternative is using angular.bind:
app.controller('Ctrl', function
($scope) {
this.name = 'name';
$scope.$watch(angular.bind(function () {
return this.title
}), function (oldVal, newVal) {
});
});
How can I declare controllerAs without using
the DOM attributes?
In the case of directives, you have the controllerAs property inside the
directive signature:
app.directive('Directive',
function () {
return {
restrict: 'EA',
templateUrl: 'template.html',
scope: true,
controller: function () {},
controllerAs: 'vm'
}
});
Or for controllers in the $routeProvider:
app.config(function
($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'main.html',
controllerAs: 'main',
controller: 'MainCtrl'
})
});
Nice blog.That is very interesting; you are a very skilled blogger. I have shared your website in my social networks! A very nice guide.
ReplyDeleteweb designing companies in madhapur
cheap website designers in hyderabad
Hiiii...Thanks for sharing Great information...Nice post...Keep move on...
ReplyDeleteAngular JS Training in Hyderabad
This is really impressive post, I am inspired with your post, do post more blogs like this, I am waiting for your blogs.
ReplyDeleteFull Stack Online Training