Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Angular 2

Introduction to Angular 2

Brief introduction to ECMAScript 2015, ECMAScript 2016, TypeScript and Angular 2.
If you want to practice your skills after completing the presentation, take a look at this exercise: https://github.com/mgechev/angular2-github-app-bootstrap

The slides and the exercise are based on Angular 2 alpha28.

Minko Gechev

June 29, 2015
Tweet

More Decks by Minko Gechev

Other Decks in Programming

Transcript

  1. Introduction to Angular 2
    Minko Gechev
    github.com/mgechev
    twitter.com/mgechev
    blog.mgechev.com

    View Slide

  2. Minko Gechev
    github.com/mgechev
    twitter.com/mgechev
    {
    "job": "Freelancer",
    "hobbies": [
    "open source",
    "blogging",
    "teaching",
    "sports"
    ],
    "communityEvents": [
    "SofiaJS",
    "BeerJS Sofia"
    ]
    }

    View Slide

  3. Angular 2
    (quick recap)

    View Slide

  4. – angular.io
    “Angular is a development platform for building
    mobile and desktop web applications”

    View Slide

  5. Client Server

    View Slide

  6. Client Server
    GET

    View Slide

  7. Client Server
    GET

    View Slide

  8. Client Server
    GET
    POST

    View Slide

  9. Client Server
    GET
    POST

    View Slide

  10. Client Server
    GET
    POST
    Angular 2

    View Slide

  11. Written in AtSc…TypeScript?

    View Slide

  12. View Slide

  13. TypeScript
    Superset of JavaScript
    • Strongly & statically typed
    • By Microsoft

    View Slide

  14. Component based

    View Slide

  15. View Slide

  16. View Slide

  17. List
    Post
    Vote
    Label
    Button
    Label

    View Slide

  18. List
    Post
    Vote
    Label
    Button
    Label

    View Slide

  19. One-way Data Flow

    View Slide

  20. View Slide

  21. View Slide

  22. A
    B C
    D E F

    View Slide

  23. Based on the
    Web Standards

    View Slide

  24. Web Components

    View Slide

  25. New Router

    View Slide

  26. Angular 1 Router

    View Slide

  27. View Slide

  28. Real Modules

    View Slide

  29. Angular 1 Modules

    View Slide

  30. View Slide

  31. No More $scope.$apply

    View Slide

  32. View Slide

  33. Just to make sure we’re
    on the same page…

    View Slide

  34. ECMAScript 5
    Property Descriptors
    (quick recap)

    View Slide

  35. ECMAScript 5 Property Descriptor
    Object.defineProperty(obj, 'name', {
    set: function (val) {
    console.log('Setting the value');
    this._name = val;
    },
    get: function (val) {
    console.log('Getting the value');
    return this._name;
    }
    });
    obj.name = 'foo';
    console.log(obj.name);
    // Setting the value
    // Getting the value
    // foo

    View Slide

  36. ECMAScript 5 Property Descriptor
    Object.defineProperty(obj, 'name', {
    set: function (val) {
    console.log('Setting the value');
    this._name = val;
    },
    get: function (val) {
    console.log('Getting the value');
    return this._name;
    }
    });
    obj.name = 'foo';
    console.log(obj.name);
    // Setting the value
    // Getting the value
    // foo

    View Slide

  37. ECMAScript 5 Property Descriptor
    Object.defineProperty(obj, 'name', {
    set: function (val) {
    console.log('Setting the value');
    this._name = val;
    },
    get: function (val) {
    console.log('Getting the value');
    return this._name;
    }
    });
    obj.name = 'foo';
    console.log(obj.name);
    // Setting the value
    // Getting the value
    // foo

    View Slide

  38. ECMAScript 5 Property Descriptor
    Object.defineProperty(obj, 'name', {
    set: function (val) {
    console.log('Setting the value');
    this._name = val;
    },
    get: function (val) {
    console.log('Getting the value');
    return this._name;
    }
    });
    obj.name = 'foo';
    console.log(obj.name);
    // Setting the value
    // Getting the value
    // foo

    View Slide

  39. ECMAScript 5 Property Descriptor
    Object.defineProperty(obj, 'name', {
    set: function (val) {
    console.log('Setting the value');
    this._name = val;
    },
    get: function (val) {
    console.log('Getting the value');
    return this._name;
    }
    });
    obj.name = 'foo';
    console.log(obj.name);
    // Setting the value
    // Getting the value
    // foo

    View Slide

  40. ECMAScript 5 Property Descriptor
    Object.defineProperty(obj, 'name', {
    set: function (val) {
    console.log('Setting the value');
    this._name = val;
    },
    get: function (val) {
    console.log('Getting the value');
    return this._name;
    }
    });
    obj.name = 'foo';
    console.log(obj.name);
    // Setting the value
    // Getting the value
    // foo

    View Slide

  41. ECMAScript 2015
    (quick recap)

    View Slide

  42. “ES2015 classes are a simple sugar over the prototype-
    based OO pattern…”
    Classes

    View Slide

  43. ECMAScript 6 Classes
    class Developer extends Person {
    constructor(name, language) {
    super(name);
    this._language = language;
    }
    get language() {
    return this._language;
    }
    set language(language) {
    this.doSomethingElse();
    this._language = language;
    }
    talk() {
    super.talk();
    console.log(`I'm a professional ${this.language} developer`);
    }
    }

    View Slide

  44. ECMAScript 6 Classes
    class Developer extends Person {
    constructor(name, language) {
    super(name);
    this._language = language;
    }
    get language() {
    return this._language;
    }
    set language(language) {
    this.doSomethingElse();
    this._language = language;
    }
    talk() {
    super.talk();
    console.log(`I'm a professional ${this.language} developer`);
    }
    }

    View Slide

  45. ECMAScript 6 Classes
    class Developer extends Person {
    constructor(name, language) {
    super(name);
    this._language = language;
    }
    get language() {
    return this._language;
    }
    set language(language) {
    this.doSomethingElse();
    this._language = language;
    }
    talk() {
    super.talk();
    console.log(`I'm a professional ${this.language} developer`);
    }
    }

    View Slide

  46. ECMAScript 6 Classes
    class Developer extends Person {
    constructor(name, language) {
    super(name);
    this._language = language;
    }
    get language() {
    return this._language;
    }
    set language(language) {
    this.doSomethingElse();
    this._language = language;
    }
    talk() {
    super.talk();
    console.log(`I'm a professional ${this.language} developer`);
    }
    }

    View Slide

  47. ECMAScript 6 Classes
    class Developer extends Person {
    constructor(name, language) {
    super(name);
    this._language = language;
    }
    get language() {
    return this._language;
    }
    set language(language) {
    this.doSomethingElse();
    this._language = language;
    }
    talk() {
    super.talk();
    console.log(`I'm a professional ${this.language} developer`);
    }
    }

    View Slide

  48. “Arrows are a function shorthand using the =>
    syntax…Unlike functions, arrows share the same
    lexical this as their surrounding code.”
    Arrow Functions

    View Slide

  49. “Arrows are a function shorthand using the =>
    syntax…Unlike functions, arrows share the same
    lexical this as their surrounding code.”
    Arrow Functions

    View Slide

  50. Arrow Functions
    [1, 2, 3, 4].reduce((a, c) => a + c, 0);
    [1, 2, 3].map(c => c + 1);
    function Developer() {
    this.talk = () => {
    console.log(`I speak ${this._language} fluently`);
    };
    }

    View Slide

  51. Arrow Functions
    [1, 2, 3, 4].reduce((a, c) => a + c, 0);
    [1, 2, 3].map(c => c + 1);
    function Developer() {
    this.talk = () => {
    console.log(`I speak ${this._language} fluently`);
    };
    }

    View Slide

  52. Arrow Functions
    [1, 2, 3, 4].reduce((a, c) => a + c, 0);
    [1, 2, 3].map(c => c + 1);
    function Developer() {
    this.talk = () => {
    console.log(`I speak ${this._language} fluently`);
    };
    }

    View Slide

  53. Arrow Functions
    [1, 2, 3, 4].reduce((a, c) => a + c, 0);
    [1, 2, 3].map(c => c + 1);
    function Developer() {
    this.talk = () => {
    console.log(`I speak ${this._language} fluently`);
    };
    }

    View Slide

  54. Let
    “Let allows block scope definition of variables.”

    View Slide

  55. Functional lexical scope
    for (var i = 0; i < 10; i += 1) {
    var foo = i + 1;
    }
    console.log(typeof i); // number
    console.log(typeof foo); // number

    View Slide

  56. Local lexical scope
    for (let i = 0; i < 10; i += 1) {
    let foo = i + 1;
    }
    console.log(typeof i); // undefined
    console.log(typeof foo); // undefined

    View Slide

  57. Promises
    “Promises could be used instead of callbacks for
    handling asynchronous actions. They are used as
    containers for resolving “future” values.”

    View Slide

  58. Promises
    fetch('/data.json')
    .then(data => {
    return data.json();
    }, error => {
    console.error(error);
    })
    .then(json => doStuff(json));

    View Slide

  59. Promises
    Promise.all([
    fetch('/a.json'),
    fetch('/b.json'),
    fetch('/c.json')
    ]).then(res => {
    return Promise.all([
    res[0].text(),
    res[1].text(),
    res[2].text()
    ]);
    })
    .then(data => {
    console.log(data.join(''));
    });

    View Slide

  60. Modules
    “Language-level support for modules for component
    definition.”

    View Slide

  61. Modules
    “Language-level support for modules for component
    definition.”

    View Slide

  62. Modules
    // Developer.js
    export default class Developer {
    // ...
    }
    // app.js
    import Developer from './Developer';
    // Math.js
    let log2 = Math.log2.bind(Math);
    let sin = Math.sin.bind(Math);
    export {
    log2,
    sin
    };
    // app.js
    import * as math from './Math';
    math.log2(10);

    View Slide

  63. Modules
    // Developer.js
    export default class Developer {
    // ...
    }
    // app.js
    import Developer from './Developer';
    // Math.js
    let log2 = Math.log2.bind(Math);
    let sin = Math.sin.bind(Math);
    export {
    log2,
    sin
    };
    // app.js
    import * as math from './Math';
    math.log2(10);

    View Slide

  64. Modules
    // Developer.js
    export default class Developer {
    // ...
    }
    // app.js
    import Developer from './Developer';
    // Math.js
    let log2 = Math.log2.bind(Math);
    let sin = Math.sin.bind(Math);
    export {
    log2, // same as log2: log2
    sin
    };
    // app.js
    import * as math from './Math';
    math.log2(10);

    View Slide

  65. Module Loaders
    “Additional imperative API to the declarative
    module syntax, which allows you to programmatically
    work with modules and configure the module loading.”

    View Slide

  66. Module Loaders
    System.import('/app')
    .then(m => m.init(),
    e => console.error(e));

    View Slide

  67. ECMAScript 2016

    View Slide

  68. – github.com/wycats/javascript-decorators
    “Decorators make it possible to annotate and modify
    classes and properties at design time.”
    ES2016 Decorators

    View Slide

  69. Decorators
    @Aspect
    class LoggingAspect {
    @Before(/.*/, /.*/)
    before(args) {
    console.log(`${args.name} called with ${args.args}`);
    }
    @After(/.*/, /.*/)
    after(args) {
    console.log(`${args.name} execution completed`);
    }
    @OnThow(/.*/, /.*/)
    errorHandler(args) {
    console.error(`${args.name} threw an error`, args.error);
    }
    }

    View Slide

  70. Decorators
    @Aspect
    class LoggingAspect {
    @Before(/.*/, /.*/)
    before(args) {
    console.log(`${args.name} called with ${args.args}`);
    }
    @After(/.*/, /.*/)
    after(args) {
    console.log(`${args.name} execution completed`);
    }
    @OnThow(/.*/, /.*/)
    errorHandler(args) {
    console.error(`${args.name} threw an error`, args.error);
    }
    }

    View Slide

  71. TypeScript
    (quick recap)

    View Slide

  72. View Slide

  73. View Slide

  74. TypeScript
    • Superset of ECMAScript
    • Allows optional static typing
    • Better support by text editors/IDEs
    • Reduce bugs
    • Faster code

    View Slide

  75. View Slide

  76. TypeScript Class
    class Developer {
    age:string;
    constructor(private languages:string[], private name:string, age) {
    this.age = (age).toString(2);
    }
    private codeInPHP() {
    // body
    }
    public writeSoftware() {
    // body
    }
    public coffeeBreak(nextTask:{(name:string):void}) {
    setTimeout(nextTask, 1000);
    }
    }

    View Slide

  77. TypeScript Class
    class Developer {
    age:string;
    constructor(private languages:string[], private name:string, age) {
    this.age = (age).toString(2);
    }
    private codeInPHP() {
    // body
    }
    public writeSoftware() {
    // body
    }
    public coffeeBreak(nextTask:{(name:string):void}) {
    setTimeout(nextTask, 1000);
    }
    }

    View Slide

  78. TypeScript Class
    class Developer {
    age:string;
    constructor(private languages:string[], private name:string, age) {
    this.age = (age).toString(2);
    }
    private codeInPHP() {
    // body
    }
    public writeSoftware() {
    // body
    }
    public coffeeBreak(nextTask:{(name:string):void}) {
    setTimeout(nextTask, 1000);
    }
    }

    View Slide

  79. TypeScript Class
    class Developer {
    age:string;
    constructor(private languages:string[], private name:string, age) {
    this.age = (age).toString(2);
    }
    private codeInPHP() {
    // body
    }
    public writeSoftware() {
    // body
    }
    public coffeeBreak(nextTask:{(name:string):void}) {
    setTimeout(nextTask, 1000);
    }
    }

    View Slide

  80. TypeScript Class
    class Developer {
    age:string;
    constructor(private languages:string[], private name:string, age) {
    this.age = (age).toString(2);
    }
    private codeInPHP() {
    // body
    }
    public writeSoftware() {
    // body
    }
    public coffeeBreak(nextTask:{(name:string):void}) {
    setTimeout(nextTask, 1000);
    }
    }

    View Slide

  81. TypeScript Class
    class Developer {
    age:string;
    constructor(private languages:string[], private name:string, age) {
    this.age = (age).toString(2);
    }
    private codeInPHP() {
    // body
    }
    public writeSoftware() {
    // body
    }
    public coffeeBreak(nextTask:{(name:string):void}) {
    setTimeout(nextTask, 1000);
    }
    }

    View Slide

  82. Interfaces

    View Slide

  83. Interfaces
    interface A {
    foo():void;
    bar(a:number):string;
    }
    interface B {
    baz(a:string):string
    }
    interface C extends A, B {
    }
    class D implements C {
    // ...
    }

    View Slide

  84. Interfaces
    interface A {
    foo():void;
    bar(a:number):string;
    }
    interface B {
    baz(a:string):string
    }
    interface C extends A, B {
    }
    class D implements C {
    // ...
    }

    View Slide

  85. Interfaces
    interface A {
    foo():void;
    bar(a:number):string;
    }
    interface B {
    baz(a:string):string
    }
    interface C extends A, B {
    }
    class D implements C {
    // ...
    }

    View Slide

  86. Interfaces
    interface A {
    foo():void;
    bar(a:number):string;
    }
    interface B {
    baz(a:string):string
    }
    interface C extends A, B {
    }
    class D implements C {
    // ...
    }

    View Slide

  87. Type Inference

    View Slide

  88. Type Inference
    let answer = 42;
    let callback:{(a:number, ...nums:any[]):number};
    callback = (a, nums) => nums.reduce((a, c) => a + c, a);
    let foo;
    foo = 42;

    View Slide

  89. Type Inference
    let answer = 42;
    let callback:{(a:number, ...nums:any[]):number};
    callback = (a, nums) => nums.reduce((a, c) => a + c, a);
    let foo;
    foo = 42;

    View Slide

  90. Type Inference
    let answer = 42;
    let callback:{(a:number, ...nums:any[]):number};
    callback = (a, nums) => nums.reduce((a, c) => a + c, a);
    let foo;
    foo = 42;

    View Slide

  91. Type Inference
    let answer = 42;
    let callback:{(a:number, ...nums:any[]):number};
    callback = (a, nums) => nums.reduce((a, c) => a + c, a);
    let foo;
    foo = 42;

    View Slide

  92. Adopting Existing Libraries

    View Slide

  93. Ambient Declarations
    interface JQueryStatic {
    /**
    * Perform an asynchronous HTTP (Ajax) request.
    *
    * @param settings A set of key/value pairs that …
    */
    ajax(settings: JQueryAjaxSettings): JQueryXHR;
    /**
    * Perform an asynchronous HTTP (Ajax) request.
    *
    * @param url A string containing the URL to which the request is sent.
    * @param settings A set of key/value pairs that…
    */
    ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR;
    // ...
    }
    declare var jQuery: JQueryStatic;
    declare var $: JQueryStatic;

    View Slide

  94. Add Type Definition Reference
    ///
    let elems = $('.elems');
    //...

    View Slide

  95. View Slide

  96. Main Concepts

    View Slide

  97. Annotations

    View Slide

  98. Annotations
    import {Component, View, NgFor} from 'angular2/angular2';
    import {Home} from './components/home/home';
    import {About} from './components/about/about';
    @Component({
    selector: 'app'
    })
    @RouteConfig([
    { path: '/', component: Home, as: 'home' },
    { path: '/about', component: About, as: 'about' }
    ])
    @View({
    templateUrl: './app.html?v=<%= VERSION %>',
    directives: [RouterOutlet, RouterLink]
    })
    class App {}

    View Slide

  99. Annotations
    import {Component, View, NgFor} from 'angular2/angular2';
    import {Home} from './components/home/home';
    import {About} from './components/about/about';
    @Component({
    selector: 'app'
    })
    @RouteConfig([
    { path: '/', component: Home, as: 'home' },
    { path: '/about', component: About, as: 'about' }
    ])
    @View({
    templateUrl: './app.html?v=<%= VERSION %>',
    directives: [RouterOutlet, RouterLink]
    })
    class App {}

    View Slide

  100. View Slide

  101. ES7 Decorators != Angular Annotations

    View Slide

  102. ES7 Decorators != Angular Annotations
    Annotations are implemented with
    decorators

    View Slide

  103. Directives

    View Slide

  104. Directives
    A few directives…
    • ng-for
    • ng-if
    • ng-switch
    • ng-style

    View Slide

  105. ng-if
    *ng-if="selectedUser !== null">

    View Slide

  106. ng-for


    {{user}}


    View Slide

  107. Directives
    Components

    View Slide

  108. UserDetails.ts
    import {Component, View} from ‘angular2/angular2';
    import {NgIf} from 'angular2/angular2';
    @Component({
    selector: 'user-details',
    properties: ['user']
    })
    @View({
    templateUrl: ‘./user-details.html’,
    directives: [NgIf]
    })
    export class UserDetails {
    user:any;
    constructor() {}
    }

    View Slide

  109. UserDetails.ts
    import {Component, View} from ‘angular2/angular2';
    import {NgIf} from 'angular2/angular2';
    @Component({
    selector: 'user-details',
    properties: ['user']
    })
    @View({
    templateUrl: ‘./user-details.html’,
    directives: [NgIf]
    })
    export class UserDetails {
    user:any;
    constructor() {}
    }

    View Slide

  110. UserDetails.ts
    import {Component, View} from ‘angular2/angular2';
    import {NgIf} from 'angular2/angular2';
    @Component({
    selector: 'user-details',
    properties: ['user']
    })
    @View({
    templateUrl: ‘./user-details.html’,
    directives: [NgIf]
    })
    export class UserDetails {
    user:any;
    constructor() {}
    }

    View Slide

  111. Services

    View Slide

  112. View Slide

  113. Service.ts
    @Injectable()
    export class Http {
    constructor(private _backend: XHRBackend,
    private _defaultOptions: BaseRequestOptions) {}
    get(url: string, options?: IRequestOptions) {
    return httpRequest(this._backend,
    new Request(url, this._defaultOptions.merge(options)
    .merge({method: RequestMethods.GET})));
    }
    post(url: string, body: any, options?: IRequestOptions) {
    return httpRequest(this._backend,
    new Request(url, this._defaultOptions.merge(options)
    .merge({body: body, method: RequestMethods.POST})));
    }
    }

    View Slide

  114. Service.ts
    @Injectable()
    export class Http {
    constructor(private _backend: XHRBackend,
    private _defaultOptions: BaseRequestOptions) {}
    get(url: string, options?: IRequestOptions) {
    return httpRequest(this._backend,
    new Request(url, this._defaultOptions.merge(options)
    .merge({method: RequestMethods.GET})));
    }
    post(url: string, body: any, options?: IRequestOptions) {
    return httpRequest(this._backend,
    new Request(url, this._defaultOptions.merge(options)
    .merge({body: body, method: RequestMethods.POST})));
    }
    }

    View Slide

  115. Service.ts
    @Injectable()
    export class Http {
    constructor(private _backend: XHRBackend,
    private _defaultOptions: BaseRequestOptions) {}
    get(url: string, options?: IRequestOptions) {
    return httpRequest(this._backend,
    new Request(url, this._defaultOptions.merge(options)
    .merge({method: RequestMethods.GET})));
    }
    post(url: string, body: any, options?: IRequestOptions) {
    return httpRequest(this._backend,
    new Request(url, this._defaultOptions.merge(options)
    .merge({body: body, method: RequestMethods.POST})));
    }
    }

    View Slide

  116. Change Detection

    View Slide

  117. A
    B E
    D
    C

    View Slide

  118. A
    B E
    D
    C

    View Slide

  119. A
    B E
    D
    C

    View Slide

  120. A
    B E
    D
    C

    View Slide

  121. Detection mechanisms
    • No front-end state
    • Event based
    • Difference based
    • Dirty checking

    View Slide

  122. No front-end state

    View Slide

  123. Server

    View Slide

  124. Server

    View Slide

  125. Server

    View Slide

  126. Event Based

    View Slide

  127. A
    B E
    D
    C

    View Slide

  128. A
    B E
    D
    C
    Change Event

    View Slide

  129. A
    B E
    D
    C

    View Slide

  130. Difference Based

    View Slide

  131. A
    B E
    D
    C
    Page
    Body Header
    Content
    Sidebar

    View Slide

  132. A
    B E
    D
    C
    Page
    Body Header
    Content
    Sidebar

    View Slide

  133. A
    B E
    D
    C
    Page
    Body Header
    Content
    Sidebar
    Page
    Body Header
    Content
    Sidebar

    View Slide

  134. A
    B E
    D
    C

    View Slide

  135. A
    B E
    D
    C
    Page
    Body Header
    Content
    Sidebar

    View Slide

  136. Dirty Checking

    View Slide


  137. {{user.name}}

    View Slide

  138. addWatcher({
    last: eval('user.name');
    exp: 'user.name',
    fn: result => {
    element.text(result);
    }
    });

    {{user.name}}

    View Slide

  139. Dirty Checking
    let digest = (component) => {
    let dirty, watcher, current, i;
    let { watchers, children } = component;
    do {
    dirty = false;
    for (i = 0; i < watchers.length; i++) {
    watcher = watchers[i];
    current = eval(watcher.exp);
    if (!equals(watcher.last, current)) {
    watcher.last = clone(current);
    dirty = true;
    watcher.fn(current);
    }
    }
    } while (dirty);
    for (i = 0; i < children.length; i++)
    digest(children[i]);
    };

    View Slide

  140. Dirty Checking
    let digest = (component) => {
    let dirty, watcher, current, i;
    let { watchers, children } = component;
    do {
    dirty = false;
    for (i = 0; i < watchers.length; i++) {
    watcher = watchers[i];
    current = eval(watcher.exp);
    if (!equals(watcher.last, current)) {
    watcher.last = clone(current);
    dirty = true;
    watcher.fn(current);
    }
    }
    } while (dirty);
    for (i = 0; i < children.length; i++)
    digest(children[i]);
    };

    View Slide

  141. Dirty Checking
    let digest = (component) => {
    let dirty, watcher, current, i;
    let { watchers, children } = component;
    do {
    dirty = false;
    for (i = 0; i < watchers.length; i++) {
    watcher = watchers[i];
    current = eval(watcher.exp);
    if (!equals(watcher.last, current)) {
    watcher.last = clone(current);
    dirty = true;
    watcher.fn(current);
    }
    }
    } while (dirty);
    for (i = 0; i < children.length; i++)
    digest(children[i]);
    };

    View Slide

  142. Dirty Checking
    let digest = (component) => {
    let dirty, watcher, current, i;
    let { watchers, children } = component;
    do {
    dirty = false;
    for (i = 0; i < watchers.length; i++) {
    watcher = watchers[i];
    current = eval(watcher.exp);
    if (!equals(watcher.last, current)) {
    watcher.last = clone(current);
    dirty = true;
    watcher.fn(current);
    }
    }
    } while (dirty);
    for (i = 0; i < children.length; i++)
    digest(children[i]);
    };

    View Slide

  143. Dirty Checking
    let digest = (component) => {
    let dirty, watcher, current, i;
    let { watchers, children } = component;
    do {
    dirty = false;
    for (i = 0; i < watchers.length; i++) {
    watcher = watchers[i];
    current = eval(watcher.exp);
    if (!equals(watcher.last, current)) {
    watcher.last = clone(current);
    dirty = true;
    watcher.fn(current);
    }
    }
    } while (dirty);
    for (i = 0; i < children.length; i++)
    digest(children[i]);
    };

    View Slide

  144. List
    Post
    Vote
    Label
    Button
    Label

    View Slide

  145. List
    Post
    Vote
    Label
    Button
    Label
    Click!

    View Slide

  146. List
    Post
    Vote
    Label
    Button
    Label

    View Slide

  147. View Slide

  148. Not exactly…

    View Slide

  149. List
    Post
    Vote
    Label
    Button
    Label
    Click!

    View Slide

  150. List
    Post
    Vote
    Label
    Button
    Label

    View Slide

  151. What about two-way data
    binding?

    View Slide

  152. Two-way binding
    input.onchange = () => {
    component[property] = input.value;
    digest();
    };
    addWatcher(property, (val) => {
    input.value = val;
    });

    View Slide

  153. What if…

    View Slide

  154. Two-way binding
    input.onchange = () => {
    component[property] = input.value;
    digest();
    };
    addWatcher(property, (val) => {
    input.value = val;
    });

    View Slide

  155. Two-way binding
    input.onchange = () => {
    component[property] = input.value;
    digest();
    };
    addWatcher(property, (val) => {
    input.value = val + 1;
    });

    View Slide

  156. Two-way binding
    input.onchange = () => {
    component[property] = input.value;
    digest();
    };
    addWatcher(property, (val) => {
    input.value = val + 1;
    });

    View Slide

  157. Two-way binding
    input.onchange = () => {
    component[property] = input.value;
    digest();
    };
    addWatcher(property, (val) => {
    input.value = val + 1;
    });

    View Slide

  158. Two-way binding
    input.onchange = () => {
    component[property] = input.value;
    digest();
    };
    addWatcher(property, (val) => {
    input.value = val + 1;
    });

    View Slide

  159. Two-way binding
    input.onchange = () => {
    component[property] = input.value;
    digest();
    };
    addWatcher(property, (val) => {
    input.value = val + 1;
    });

    View Slide

  160. No two-way data binding

    View Slide

  161. Zone

    View Slide

  162. The dirty checking should be
    run on any change

    View Slide

  163. Zone monkey patches
    standard async APIs

    View Slide

  164. Zone helps us keep track of
    the changes

    View Slide

  165. unbuffer x | unbuffer
    command
    done
    find
    echo
    echo
    Pipes
    find
    ls
    ls
    command
    # process each line, using variables as parsed into $var1, $var2, etc
    # (note that this may be a subshell: var1, var2 etc will not be available
    # after the while loop terminates; some shells, such as zsh and newer
    # versions of Korn shell, process the commands to the left of the pipe
    # operator in a subshell)
    done

    View Slide

  166. Pipe Interface
    export interface Pipe {
    supports(obj): boolean;
    onDestroy(): void;
    transform(value: any): any;
    }

    View Slide

  167. Pipes
    A way of extending the change detection
    • Format data
    • Perform smarter change detection

    View Slide

  168. Dynamic Change Detector
    _pipeCheck(proto: ProtoRecord, throwOnChange: boolean) {
    // ...
    var currValue = pipe.transform(context);
    if (!isSame(prevValue, currValue)) {
    // ...
    this._setChanged(proto, true);
    return change;
    } else {
    // ...
    this._setChanged(proto, true);
    return null;
    }
    } else {
    // ...
    this._setChanged(proto, false);
    return null;
    }
    }

    View Slide

  169. Pipes
    A few examples:
    • IterableChanges
    • PromisePipe
    • UpperCasePipe
    • ObservablePipe
    • JsonPipe

    View Slide

  170. PromisePipe

    {{ description | async }}

    View Slide

  171. UpperCasePipe

    {{ "foo" | UpperCase }}

    View Slide

  172. IterableDiff (foreach.js)
    set ngForOf(value: any) {
    this._ngForOf = value;
    this._pipe =
    this.pipes
    .get("iterableDiff",…);
    }

    View Slide

  173. Dependency Injection

    View Slide

  174. Router

    View Slide

  175. Router
    import
    {RouteConfig,
    RouterOutlet,
    RouterLink,
    routerInjectables}
    from 'angular2/router';
    @Component({
    selector: 'app'
    })
    @RouteConfig([
    { path: '/', component: Home, as: 'home' },
    { path: '/about', component: About, as: 'about' }
    ])
    @View({
    templateUrl: './app.html',
    directives: [RouterOutlet, RouterLink]
    })
    class App {}
    bootstrap(App, [routerInjectables]);

    View Slide

  176. Router
    import
    {RouteConfig,
    RouterOutlet,
    RouterLink,
    routerInjectables}
    from 'angular2/router';
    @Component({
    selector: 'app'
    })
    @RouteConfig([
    { path: '/', component: Home, as: 'home' },
    { path: '/about', component: About, as: 'about' }
    ])
    @View({
    templateUrl: './app.html',
    directives: [RouterOutlet, RouterLink]
    })
    class App {}
    bootstrap(App, [routerInjectables]);

    View Slide

  177. Router
    import
    {RouteConfig,
    RouterOutlet,
    RouterLink,
    routerInjectables}
    from 'angular2/router';
    @Component({
    selector: 'app'
    })
    @RouteConfig([
    { path: '/', component: Home, as: 'home' },
    { path: '/about', component: About, as: 'about' }
    ])
    @View({
    templateUrl: './app.html',
    directives: [RouterOutlet, RouterLink]
    })
    class App {}
    bootstrap(App, [routerInjectables]);

    View Slide

  178. Router
    import
    {RouteConfig,
    RouterOutlet,
    RouterLink,
    routerInjectables}
    from 'angular2/router';
    @Component({
    selector: 'app'
    })
    @RouteConfig([
    { path: '/', component: Home, as: 'home' },
    { path: '/about', component: About, as: 'about' }
    ])
    @View({
    templateUrl: './app.html',
    directives: [RouterOutlet, RouterLink]
    })
    class App {}
    bootstrap(App, [routerInjectables]);

    View Slide

  179. Router
    import
    {RouteConfig,
    RouterOutlet,
    RouterLink,
    routerInjectables}
    from 'angular2/router';
    @Component({
    selector: 'app'
    })
    @RouteConfig([
    { path: '/', component: Home, as: 'home' },
    { path: '/about', component: About, as: 'about' }
    ])
    @View({
    templateUrl: './app.html',
    directives: [RouterOutlet, RouterLink]
    })
    class App {}
    bootstrap(App, [routerInjectables]);

    View Slide

  180. Router Directives


    Home
    About



    View Slide

  181. Router Directives


    Home
    About



    View Slide

  182. Router Directives


    Home
    About



    View Slide

  183. References
    • Angular 2 Official Website
    • Change And Its Detection In JavaScript Frameworks
    • Angular2 - First Impressions
    • ng-conf 2015 Keynote 2 - Misko Hevery and Rado Kirov
    • angular2-seed
    • angular2-education

    View Slide

  184. Thank you!
    github.com/mgechev
    twitter.com/mgechev
    blog.mgechev.com

    View Slide