Евгений Жарков AngularJS: Good parts
-
Upload
fwdays -
Category
Technology
-
view
669 -
download
1
Transcript of Евгений Жарков AngularJS: Good parts
Watchers ]:>
Track Watchers
Angular adds a watcher to the digest cycle for each of these:• {{expression}} — templates• $scope.$watch — in the code
Track WatchersfunctiongetWatchers(root){root=angular.element(root||document.documentElement);varwatcherCount=0;functiongetElemWatchers(element){varisolateWatchers=getWatchersFromScope(element.data().$isolateScope);varscopeWatchers=getWatchersFromScope(element.data().$scope);varwatchers=scopeWatchers.concat(isolateWatchers);angular.forEach(element.children(),function(childElement){watchers=watchers.concat(getElemWatchers(angular.element(childElement)));});returnwatchers;}functiongetWatchersFromScope(scope){if(scope){returnscope.$$watchers||[];}else{return[];}}returngetElemWatchers(root);}
https://gist.github.com/kentcdodds/31c90402750572107922
Track Watchers
//getallwatchersonthewholepagegetWatchers();//getwatchersofaspecificelement(anditschildren)getWatchers(document.body);//selecttheelementofinterestinChromeDevtoolsgetWatchers($0);
Track Watchers
https://github.com/kentcdodds/ng-stats
AngularJS > ES6
ES6, require.js
functionMainController(){……………}
export{MainController}
—————————————————————————————————————
import{MainController}from‘./path/to/MainController';……………
ES6, require.jsclassMainController{
constructor(searchService){this.searchService=searchService;}
search(){this.searchService.fetch(this.searchTerm).then(response=>{this.items=response.data.items;});}}
export{MainController}
ES6, require.js
import{MainController}from'./MainController';
import{SearchService}from'./SearchService';
angular
.module('app',[])
.controller('mainController',MainController)
.service('searchService',SearchService);
Inheritance
classPageController{
constructor(title){
this._title=title;}
title(){
return'Title:'+this._title;}}
export{PageController}
Inheritance
import{PageController}from'./PageController';
classProductPageControllerextendsPageController{
constructor(){
super('ES6inheritancewithAngular’);
}}
export{ProductPageController}
Inheritance
import{ProductPageController}from'./ProductPageController';
angular
.module('app',[])
.controller('ProductPageController',ProductPageController);
Service Inheritance
myModule.service(fn)
YES, instantiated with the new operator under the hood
myModule.factory(fn)
NO
Don’t forget about minification
MainController.$inject=['SearchService'];
and/or ng-annotate
exportdefaultclassNameService{
/*@ngInject*/
constructor($q){..}
}
ES6 Babel Browserify Boilerplate
https://github.com/thoughtram/es6-babel-browserify-boilerplate
Angular ES6
https://github.com/michaelbromley/angular-es6
AngularJS > ES6 > Tests
ES5, Karma, Jasmine, PhantomJSdescribe('TodoService',function(){
varTodoService,InitialTodosMock;//InstantiateAngularJScontextbeforeEach(module("app"));//RegistermocksinAngularJScontextbeforeEach(module(function($provide){InitialTodosMock=[{label:'Testtodo',done:false}];$provide.value('initialTodos',InitialTodosMock);}));//GetinstanceofTodoServicewithmockeddependenciesfromAngularJScontextbeforeEach(inject(function(_TodoService_){TodoService=_TodoService_;}));//Oh,...dotheactualtesting!!!it('shouldhaveinitialtodo',function(){expect(TodoService.todos.length).toBe(1);expect(TodoService.todos[0].label]).toBe('Testtodo');expect(TodoService.todos[0].done]).toBe(false);
});});
ES5, Karma, Jasmine, PhantomJSdescribe('TodoController',function(){varscope,$rootScope,$controller;//InstantiateAngularJScontextbeforeEach(module('app'));//RegistermocksinAngularJScontext//(sometimesnotnecessary,wecanuserealservicestoo,buttheAngularcontextgrows...)beforeEach(module(function($provide){varTodoServiceMock={todos:[],addTodo:function(){/*……*/},toggleTodo:function(){/*……*/},removeDoneTodost(){/*……*/}};$provide.value('TodoService',TodoServiceMock);}));//GetinstanceofTodoController,youknow,createnew$scopefrom$rootScopebyyourselfandstuff...//Itispossibletonotuse$scopewhenusing'controllerAs'syntax,//butyoustillhavetouseatleast$controllertogettherefferencetocontrolleritselfbeforeEach(inject(function(_$rootScope_,_$controller_,_TodoService_){$controller=_$controller_;$rootScope=_$rootScope_;scope=$rootScope.$new();
$controller('TodoController',{$scope:scopeTodoService:_TodoService_});}));//Oh,...dotheactualtesting!!!it('shouldhaveinitialtodos',function(){expect(scope.todos.length).toBe(1);});});
Issues
• Angular context module(‘app’) must be instantiated to be able to do any testing. Without Angular context you can’t get access (reference) to your controllers / services.
• Angular and all other used libraries must be included during testing so that it is even possible to instantiate Angular context.
• Angular context can grow quite large so that it’s creation will consume considerable amount of time for every test file.
• Karma exclusion syntax doesn’t follow standard node glob pattern which can make you go crazy when you try to solve timeout errors caused by insufficient memory on PhantomJS by splitting test execution into multiple batches, while supporting dev mode single test execution (karma uses extra exclude property instead of supporting standard “!”)
ES6, Mocha, chaiimport{assert}from'chai';importTodoServicefrom'./todo.service.js';
letservice;
describe('TodoService',function(){beforeEach(function(){service=TodoService();});
it('shouldcontainemptytodosafterinitialization',function(){assert.equal(service.todos.length,0);});
it('shouldtoggletodo',function(){service.addTodo('Finishexampleproject');assert.equal(service.todos[0].done,false);service.toggleTodo('Finishexampleproject');assert.equal(service.todos[0].done,true);service.toggleTodo('Finishexampleproject');assert.equal(service.todos[0].done,false);});});
ES6, Mocha, chaiimport{assert}from'chai';importSomeComponentfrom‘./some-component';
letcomponent;
describe('some-component',function(){beforeEach(function(){component=newSomeComponent();});
it('shouldstartwithcountervalue20',function(){assert.equal(component.counter,20);});
it('shouldacceptinitialcountervalueasdependency',function(){component=newSomeComponent(30);assert.equal(component.counter,30);});
it('shouldincrementcountervalueafterincrementiscalled',function(){assert.equal(component.counter,20);component.increment();assert.equal(component.counter,21);});});
Dependencies are passed explicitly as a parameter of function
Dig, read, criticise
• Paginationhttps://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination
• angular-formly http://angular-formly.com/
• angular-translatehttps://angular-translate.github.io
• LumX (material design) http://ui.lumapps.com
angular-formly
<formly-formmodel="vm.user"fields="vm.userFields">
<buttontype="submit"class="btnbtn-default"ng-click="vm.submit(vm.user)">Submit</button>
</formly-form>
angular-formlyvm.userFields=[{key:'email',type:'input',templateOptions:{type:'email',label:'Emailaddress',placeholder:'Enteremail'}},{key:'password',type:'input',templateOptions:{type:'password',label:'Password',placeholder:'Password'}},
{key:'file',type:'file',templateOptions:{label:'Fileinput',description:'Exampleblock-levelhelptexthere',url:'https://example.com/upload'}},{key:'checked',type:'checkbox',templateOptions:{label:'Checkmeout'}}];
Pagination
<ANY
dir-paginate="expression|itemsPerPage:(int|expression)[:paginationId(stringliteral)]"
[current-page=""]
[pagination-id=""]
[total-items=""]>
...
</ANY>
Pagination
<dir-pagination-controls
[max-size=""]
[direction-links=""]
[boundary-links=""]
[on-page-change=""]
[pagination-id=""]
[template-url=""]
[auto-hide=""]>
</dir-pagination-controls>