tips for angular applications
TRANSCRIPT
© Copyright SELA software & Education Labs Ltd. | 14-18 Baruch Hirsch St Bnei Brak, 51202 Israel | www.selagroup.com
SELA DEVELOPER PRACTICEMAY 31, 2015 – JUNE 4, 2015
Sebastian Pederiva
Tips for Angular Applications
Senior Consultant
@spederiva
tiny.cc/SebastianBlog
Project Structure
Roll your own Angular Seed https://github.com/angular/angular- seed
Add Suffix to the file names
Easy to read and understandEssential for “component type” structureHelp make better automation and testing
product-list.ctrl.jsproduct-list.tpl.htmlproduct-list.fltr.jsproduct-list.fctry.jsproduct-list.srv.jsproduct-list.const.jsproduct-list.val.js
Separate to Modules
var corelist = app.module("app.core.list", []);
corelist.controller("app.core.list.listCtrl", ...)
angular.module(“app.common.services")
.service("myApp.common.services.product"
Golden RulesControllers should never refer to any DOM elementsControllers should call services vs. holding too much business logicAvoid $rootScope, try to use services insteadExpression {{}} vs ng-cloak
Minimizing Angular Files
Minimizing process will replace variable names compromising the dependency injection
someModule.controller('MyController', ['$scope', function($scope) { $scope.name = "Sebastian";
}]);
someModule.controller('MyController', function ($scope) {$scope.name = "Sebastian";
});
someModule.controller('MyController', function (a) {a.name = "Sebastian";
});
One Time Binding
Use double colon ::https://code.angularjs.org/1.3.15/docs/guide/expression#one-time-bindingFor previous versions: https://github.com/Pasvaz/bindonce
<p id="one-time-binding-example">One time binding: {{::name}}
</p>
Controller Inheritanceapp.controller("ChildCtrl", ["$scope", function ($scope) {
$scope.childText = "childText" $scope.text = "childText”
}]);
app.controller("ParentCtrl", ["$scope", function ($scope) { $scope.parentText = "parentText" $scope.text = "parentText”
}]);
<div ng-controller="ParentCtrl”> <div ng-controller="ChildCtrl”> {{parentText}} <br/> {{childText}} <br/> {{text}} </div>
</div>
Controller Inheritanceapp.controller("ChildCtrl", function ($scope, $controller) {
$controller("ParentCtrl", {$scope: $scope});
$scope.childText = "childText";$scope.text = "childText";
});
app.controller("ParentCtrl", ["$scope", function ($scope) { $scope.parentText = "parentText" $scope.text = "parentText”
}]);
<div ng-controller="ChildCtrl”> {{parentText}} <br/> {{childText}} <br/> {{text}}
</div>
Avoid Watchers$watch occurs when the users clicks on an item, not when the model changesConsider using events insteadMinimize use watchersAngular uses dirty checking to keep track of all the changes in app
$watch() vs. $watchCollection()
$watch has 3 parametersUse $watchCollection, it only checks the first layer of object’s propertieshttp://www.bennadel.com/blog/2566-scope-watch-vs-watchcollection-in-angularjs.htm
http://plnkr.co/edit/Pbvo6AqME081rZ2RVKDU?p=preview
ng-repeat, track when possiblengRepeat does not allow duplicate items in arraysTrack by to increase performanceDefault tracking<div ng-repeat=”item in collection track by $id(obj)”>
Own tracking<div ng-repeat=”item in collection track by item.id”>
https://docs.angularjs.org/api/ng/directive/ngRepeat#tracking-and-duplicates
ng-repeat
How many times will getPrice function be called? Use watch collection to calculate everything when the controller is first invoked
<tr ng-repeat="item in items"><td>{{item.name}}</td><td>{{item.description}}</td><td>{{getPrice(item.id)}}</td>
</tr>
ng-repeat cont
<tr ng-repeat="item in items"><td>{{item.name}}</td><td>{{item.description}}</td><td>{{item.price}}</td>
</tr>
$scope.$watchCollection('items', function (newItems) {for (var i = 0; i < newItems.length; i++) { newItems[i].price = getPrice(newItems.id);
}$scope.items = newItems;
});
Avoid ng-repeat for infinite scroll
Memory LeaksPerformance problemPossible solution: http://www.williambrownstreet.net/blog/2013/07/angularjs-my-solution-to-the-ng-repeat-performance-problem
Debounce ng-model
Lot of updates?
https://docs.angularjs.org/api/ng/directive/ngModelOptions <input ng-model="name”ng-model-options="{ debounce: 500 }” />
Use ng-if instead of ng-showng-show will render an element, and use display:none to hide itng-if will actually removes the element from DOM, and will re-create it, if it’s needed.
Promise you use Promises
Prefer Promises Over CallbacksFollow The ‘...ing’ ConventionClear Indication You’re getting a Promise
function gettingUsers(){return $http()...
}
gettingUsers().success().error()
Destroying Memory Leaks
Use $scope.$on('$destroy', …)Remove handlersClean up resources which won’t be garbage collected automatically
module.controller("TestController", function ($scope, $timeout) {
var onTimeout = function () {$scope.value += 1;timer = $timeout(onTimeout, 1000);
};var timer = $timeout(onTimeout, 1000);
$scope.value = 0;
$scope.$on("$destroy", function () {if (timer) {$timeout.cancel(timer);}
});});
Managing the Time…use moment.js
https://github.com/urish/angular-moment
<span am-time-ago="message.time"></span>
LoggingAvoid using console.log in your controllers Use $log instead$log can be extended to provide additional logging capabilities
Forget jQuery ExistsjQuery-- Use angular.element instead of $() selector -- Search for a jQuery-equivalent instead » Examples-- html(), text(), val() » Ask whether you can use directives instead Take a look at ui-bootstrap’s directives at https://github.com/angular-ui/bootstrap/tree/master/src
Testing
Faster Bug TrackingJasmine Givenhttp://www.airpair.com/angularjs/workshops/unit-testing-angularjs
describe("assigning stuff to this", function() { Given(function() { this.number = 24; }); Given(function() { this.number++; }); When(function() { this.number *= 2; }); Then(function() { expect(this.number).toBe(50) });});
Linkshttps://thinkster.io/angulartutorial/a-better-way-to-learn-angularjs/http://chieffancypants.github.io/angular-loading-barhttp://angular-js.inhttps://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/pub