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. Minko Gechev github.com/mgechev twitter.com/mgechev { "job": "Freelancer", "hobbies": [ "open

    source", "blogging", "teaching", "sports" ], "communityEvents": [ "SofiaJS", "BeerJS Sofia" ] }
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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`); } }
  9. 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`); } }
  10. 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`); } }
  11. 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`); } }
  12. 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`); } }
  13. “Arrows are a function shorthand using the => syntax…Unlike functions,

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

    arrows share the same lexical this as their surrounding code.” Arrow Functions
  15. 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`); }; }
  16. 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`); }; }
  17. 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`); }; }
  18. 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`); }; }
  19. 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
  20. 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
  21. Promises “Promises could be used instead of callbacks for handling

    asynchronous actions. They are used as containers for resolving “future” values.”
  22. Promises fetch('/data.json') .then(data => { return data.json(); }, error =>

    { console.error(error); }) .then(json => doStuff(json));
  23. 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('')); });
  24. 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);
  25. 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);
  26. 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);
  27. Module Loaders “Additional imperative API to the declarative module syntax,

    which allows you to programmatically work with modules and configure the module loading.”
  28. 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); } }
  29. 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); } }
  30. TypeScript • Superset of ECMAScript • Allows optional static typing

    • Better support by text editors/IDEs • Reduce bugs • Faster code
  31. 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); } }
  32. 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); } }
  33. 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); } }
  34. 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); } }
  35. 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); } }
  36. 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); } }
  37. Interfaces interface A { foo():void; bar(a:number):string; } interface B {

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

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

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

    baz(a:string):string } interface C extends A, B { } class D implements C { // ... }
  41. 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;
  42. 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;
  43. 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;
  44. 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;
  45. 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;
  46. 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 {}
  47. 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 {}
  48. 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() {} }
  49. 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() {} }
  50. 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() {} }
  51. 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}))); } }
  52. 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}))); } }
  53. 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}))); } }
  54. A B E D C Page Body Header Content Sidebar

    Page Body Header Content Sidebar
  55. 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]); };
  56. 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]); };
  57. 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]); };
  58. 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]); };
  59. 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]); };
  60. Two-way binding input.onchange = () => { component[property] = input.value;

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

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

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

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

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

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

    digest(); }; addWatcher(property, (val) => { input.value = val + 1; });
  67. 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
  68. Pipes A way of extending the change detection • Format

    data • Perform smarter change detection
  69. 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; } }
  70. 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]);
  71. 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]);
  72. 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]);
  73. 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]);
  74. 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]);
  75. 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