Евгений Жарков AngularJS: Good parts

35
AngularJS: Good parts Евгений Жарков DOOR3 @2j2e [email protected]

Transcript of Евгений Жарков AngularJS: Good parts

Page 1: Евгений Жарков AngularJS: Good parts

AngularJS: Good parts

Евгений Жарков DOOR3

@2j2e [email protected]

Page 2: Евгений Жарков AngularJS: Good parts

Watchers ]:>

Page 3: Евгений Жарков AngularJS: Good parts

Track Watchers

Angular adds a watcher to the digest cycle for each of these:• {{expression}} — templates• $scope.$watch — in the code

Page 4: Евгений Жарков AngularJS: Good parts

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

Page 5: Евгений Жарков AngularJS: Good parts

Track Watchers

//getallwatchersonthewholepagegetWatchers();//getwatchersofaspecificelement(anditschildren)getWatchers(document.body);//selecttheelementofinterestinChromeDevtoolsgetWatchers($0);

Page 6: Евгений Жарков AngularJS: Good parts
Page 7: Евгений Жарков AngularJS: Good parts

Track Watchers

Page 8: Евгений Жарков AngularJS: Good parts
Page 9: Евгений Жарков AngularJS: Good parts
Page 10: Евгений Жарков AngularJS: Good parts
Page 11: Евгений Жарков AngularJS: Good parts

https://github.com/kentcdodds/ng-stats

Page 12: Евгений Жарков AngularJS: Good parts

AngularJS > ES6

Page 13: Евгений Жарков AngularJS: Good parts

ES6, require.js

functionMainController(){……………}

export{MainController}

—————————————————————————————————————

import{MainController}from‘./path/to/MainController';……………

Page 14: Евгений Жарков AngularJS: Good parts

ES6, require.jsclassMainController{

constructor(searchService){this.searchService=searchService;}

search(){this.searchService.fetch(this.searchTerm).then(response=>{this.items=response.data.items;});}}

export{MainController}

Page 15: Евгений Жарков AngularJS: Good parts

ES6, require.js

import{MainController}from'./MainController';

import{SearchService}from'./SearchService';

angular

.module('app',[])

.controller('mainController',MainController)

.service('searchService',SearchService);

Page 16: Евгений Жарков AngularJS: Good parts

Inheritance

classPageController{

constructor(title){

this._title=title;}

title(){

return'Title:'+this._title;}}

export{PageController}

Page 17: Евгений Жарков AngularJS: Good parts

Inheritance

import{PageController}from'./PageController';

classProductPageControllerextendsPageController{

constructor(){

super('ES6inheritancewithAngular’);

}}

export{ProductPageController}

Page 18: Евгений Жарков AngularJS: Good parts

Inheritance

import{ProductPageController}from'./ProductPageController';

angular

.module('app',[])

.controller('ProductPageController',ProductPageController);

Page 19: Евгений Жарков AngularJS: Good parts

Service Inheritance

myModule.service(fn)

YES, instantiated with the new operator under the hood

myModule.factory(fn)

NO

Page 20: Евгений Жарков AngularJS: Good parts

Don’t forget about minification

MainController.$inject=['SearchService'];

Page 21: Евгений Жарков AngularJS: Good parts

and/or ng-annotate

exportdefaultclassNameService{

/*@ngInject*/

constructor($q){..}

}

Page 22: Евгений Жарков AngularJS: Good parts

ES6 Babel Browserify Boilerplate

https://github.com/thoughtram/es6-babel-browserify-boilerplate

Page 23: Евгений Жарков AngularJS: Good parts

Angular ES6

https://github.com/michaelbromley/angular-es6

Page 24: Евгений Жарков AngularJS: Good parts

AngularJS > ES6 > Tests

Page 25: Евгений Жарков AngularJS: Good parts

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);

});});

Page 26: Евгений Жарков AngularJS: Good parts

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);});});

Page 27: Евгений Жарков AngularJS: Good parts

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 “!”)

Page 28: Евгений Жарков AngularJS: Good parts

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);});});

Page 29: Евгений Жарков AngularJS: Good parts

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

Page 30: Евгений Жарков AngularJS: Good parts

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

Page 31: Евгений Жарков AngularJS: Good parts

angular-formly

<formly-formmodel="vm.user"fields="vm.userFields">

<buttontype="submit"class="btnbtn-default"ng-click="vm.submit(vm.user)">Submit</button>

</formly-form>

Page 32: Евгений Жарков AngularJS: Good parts

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'}}];

Page 33: Евгений Жарков AngularJS: Good parts

Pagination

<ANY

dir-paginate="expression|itemsPerPage:(int|expression)[:paginationId(stringliteral)]"

[current-page=""]

[pagination-id=""]

[total-items=""]>

...

</ANY>

Page 34: Евгений Жарков AngularJS: Good parts

Pagination

<dir-pagination-controls

[max-size=""]

[direction-links=""]

[boundary-links=""]

[on-page-change=""]

[pagination-id=""]

[template-url=""]

[auto-hide=""]>

</dir-pagination-controls>

Page 35: Евгений Жарков AngularJS: Good parts