__proto__ &

prototype

 

@tkssharma

github.com/tkssharma

Moving From angular 5 ---- to --- 6

Update your node version to 8 or 8.9.0 or above and Install Angular cli latest globally by npm i -g @angular/cli@latest

Angular 6 uses angular.json as configuration file instead of .anguar-cli.json

Update package.json

 

    "@angular-devkit/core": "^0.6.8",
    "@angular/animations": "6.0.7",
    "@angular/common": "6.0.7",
    "@angular/compiler": "6.0.7",
    "@angular/core": "6.0.7",
    "@angular/forms": "6.0.7",
    "@angular/platform-browser": "6.0.7",
    "@angular/platform-browser-dynamic": "6.0.7",
    "@angular/router": "6.0.7",
    "core-js": "^2.4.1",
    "marked": "^0.3.9",
    "rxjs": "^6.2.1",
    "zone.js": "^0.8.26",
    "rxjs-compat": "^6.0.0-rc.0"
Demo angular.json
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "ang2-conduit": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist",
            "index": "src/index.html",
            "main": "src/main.ts",
            "tsConfig": "src/tsconfig.app.json",
            "polyfills": "src/polyfills.ts",
            "assets": [
              "src/assets",
              "src/favicon.ico"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "ang2-conduit:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "ang2-conduit:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "ang2-conduit:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "karmaConfig": "./karma.conf.js",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "scripts": [],
            "styles": [
              "src/styles.css"
            ],
            "assets": [
              "src/assets",
              "src/favicon.ico"
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json",
              "src/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
    "ang2-conduit-e2e": {
      "root": "e2e",
      "sourceRoot": "e2e",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "./protractor.conf.js",
            "devServerTarget": "ang2-conduit:serve"
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "e2e/tsconfig.e2e.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    }
  },
  "defaultProject": "ang2-conduit",
  "schematics": {
    "@schematics/angular:component": {
      "prefix": "app",
      "styleext": "css"
    },
    "@schematics/angular:directive": {
      "prefix": "app"
    }
  }
}
RxJS upgrade and resolving conflicts
Do npm i -g rxjs-tslint and add below lint configuration in tslint.json
{
  "rulesDirectory": [
    "node_modules/rxjs-tslint"
  ],
  "rules": {
    "rxjs-collapse-imports": true,
    "rxjs-pipeable-operators-only": true,
    "rxjs-no-static-observable-methods": true,
    "rxjs-proper-imports": true
  }
}
 

Operators Name change: 


do -> tap
catch -> catchError
switch -> switchAll
finally -> finalize

All operators moved to ‘rxjs/operators'
import { map, filter, reduce } from 'rxjs/operators';

Observable creation methods are moved to ‘rxjs’
import { Observable, Subject, of, from } from 'rxjs';

Welcome to Angular 6.0

Finite Obserables ...

export class TestComponent {

  constructor(private http: Http) { }

  ngOnInit() {
    Observable.timer(1000).subscribe(console.log);
    this.http.get('http://api.com').subscribe(console.log);
  }


}

This is How you can use it ...

<div *ifRole="'admin'">
  Only for Admin
</div>

<div *ifRole="'client'">
  Only for Client
</div>

<div *ifRole="'editor'">
  Only for Editor
</div>

ViewChildren vs ContentChildren —

 

ContentChildren includes only elements that exists within the ng-content tag.


 

ViewChildren don’t include elements that exist within the ng-content tag.


 

 

 

 

 

ViewChildren vs ContentChildren —

 

 

 

 

 

 

 

ContentChildren — All child tab Instance

 

 

 

 

 

 

 

 

 

@Component({
  selector: 'tab',
  template: `
    <p>{{title}}</p>
  `,
})
export class TabComponent {
  @Input() title;
}

@Component({
  selector: 'tabs',
  template: `
    <ng-content></ng-content>
  `,
})
export class TabsComponent {
 @ContentChildren(TabComponent) tabs: QueryList<TabComponent>
 
 ngAfterContentInit() {
   this.tabs.forEach(tabInstance => console.log(tabInstance))
 }
}

@Component({
  selector: 'my-app',
  template: `
    <tabs>
     <tab title="One"></tab>
     <tab title="Two"></tab>
    </tabs>
  `,
})
export class App {}

ViewChildren decorator will return the component instance, but you can ask for other tokens:

If you want your component to notify his parent about something you can use the Output decorator with EventEmitter to create a custom event.

@Component({
  selector: 'add-todo',
  template: `
   <input type="text" placeholder="Add todo.." [formControl]="control">
   <button (click)="add.next(control.value)">Add</button>
`,
})
export class AddTodoComponent {
  control : FormControl = new FormControl("");
  @Output() add = new EventEmitter();
}








<add-todo (add)="addTodo($event)"></add-todo>

What is EventEmitter .. a subject ??

export declare class EventEmitter<T> extends Subject<T> {
    __isAsync: boolean;
    constructor(isAsync?: boolean);
    emit(value?: T): void;
    subscribe(generatorOrNext?: any, error?: any, complete?: any): any;
}

💪 You have the power of Rx 💪

@Output() add = new EventEmitter().filter(v => !!v);

@Output() add = new BehaviorSubject("Awesome").filter(v => !!v);

EventEmitters are not DOM events

they can't bubble to top of DOM

Event emitter !== DOM

You can't emit event from todo to todoPage component

Solution is

    Keep passing the event up the tree

 

export class TodoComponent {
  @Output() toggle = new EventEmitter<any>();
}

export class TodosComponent {
  @Output() toggle = new EventEmitter<any>();
}

export class TodosPageComponent {
  toggle($event) {}
}

Too much nesting here

Lets do it in native way !

@Component({
  selector: 'app-todo',
  template: `
     <p (click)="toggleTodo(todo)">
      {{todo.title}}
     </p>
   `
})
export class TodoComponent {
  @Input() todo;
  constructor(private el: ElementRef) {}

  toggleTodo(todo) {
    this.el.nativeElement
      .dispatchEvent(new CustomEvent('toggle-todo', {
        detail: todo,
        bubbles: true
      }));
  }
}

Native DOM not a good choice

Lets do using service

@Injectable()
export class TodosService {
  private _toggle = new Subject();
  toggle$ = this._toggle.asObservable();

  toggle(todo) {
    this._toggle.next(todo);
  }
}

export class TodoComponent {
  constructor(private todosService: TodosService) {}
  
  toggle(todo) {
    this.todosService.toggle(todo);
  }
}

export class TodosPageComponent {
  constructor(private todosService: TodosService) {
    todosService.toggle$.subscribe(..);
  }
}

View Encapsulation

import {Component, ViewEncapsulation} 
        from 'angular2/angular2';

@component({
    selector: 'app',
    template: `<p class="green">`,
    style: [` 
            .green { color: green}
        `],
    encapsulation: 'ViewEncapsulation.Native'
                            // .Emulated .None
})

export class App { 

       constructor() {}
}
  1. ViewEncapsulation.Emulated
    • ​angular2 view encapsulation enabled // default
  2. ViewEncapsulation.None
    • No view encapsulation​
  3. ViewEncapsulation.Native
    • ​view encapsulation using shadow dom

 

Directives


import {Directive, ElementRef} from 'angular2/angular2';

@Directive({
	selector: '[bold]'
})

export class BoldDirective {
	constructor(el: ElementRef) {
		el.nativeElement.style.fontWeight = 'bold';
	}
}
<div class="myapp">
    <p bold> Hello world </p>
</div>

Dependency Injection

class Vehicle {
    constructor() {
        var engine = new Engine();
            engine.build();
    }
}


Constructor injection

class Vehicle {
    constructor(engine: Engine) {
            engine.build();
    }
}



class Engine {
    constructor(nutsNBolts: NutsNBolts) {
            nutsNBolts.fit();
    }
}



class NutsNBolts {
    constructor() {
    .....
    }
    fit() {

    }
}



new Vehicle(new Engine(new NutsNBolts()));


// Parent component

import {Component} from 'angular2/angular2';
import {Bootstrap} from 'angular2/angular2';
import {UserService} from './userservice.js';

@Component({ template: `<div> My App </div>` ... })

export class App {
    constructor() {
     
    }
}
 
Bootstrap(App,[UserService]); //UserService available in entire app.



//Child component                                   

import {Component} from 'angular2/angular2';   
import {UserService} from './userservice.js';                          
...                                                                           
                                                                      
@Component({ ... })                                                      

export class SomeComponent {
    constructor(user: UserService) {  //Singleton 
        user.dosomething();    
    }
}

Global Injection

By default all objects injected are singleton

// parent.ts  -- parent component
import {RoutineService} from './componentservice';
import {Child} from './child';

@Component({
    ......
    template: `<div>Parent component  <child></child> </div>`,
    directives: [Child]
    providers: [RoutineService]
//    viewProviders: [RoutineService]
})

export class App {
    constructor(routineservice: RoutineService) {
         routineservice.addRoutine(["eat", "sleep", "code"]);
    }
}
//child.ts -- child component                                   

import {RoutineService} from './routineservice.js';
                                                                                                                                              
@Component({ 
    selector: 'child',
    template `<p> I am child component </p>`
})                                                      

export class SomeComponent {
    constructor(routineservice: RoutineService) {  //Singleton 
        routineservice.deleteRoutine(["sleep"]);    
    }
}

Component level injection

PIPES

<!-- Date PIPE --!>

<p>{{date | date:'mediumDate'}}</p>
    <!-- Sep 1, 2015 --!>
<p>{{date | date:'yMMMMd'}}</p>
    <!-- September 1, 2015 --!>
<p>{{date | date:'shortTime'}}</p>
    <!-- 3:50 pm --!>


<!-- CURRENCY PIPE --!>

<p>{{43 | currency: 'USD' : true}}</p>
    <!-- $43 --!>
<p>{{43 | currency: 'USD' : true : '2.2'}} </p>
    <!--$43.00 --!>
<p>{{43 | currency: 'USD' : true : '3.3'}} </p>
     <!--$043.000 --!>

Angular2 inbuilt pipes

  • currency
  • date
  • uppercase
  • json
  • limitTo
  • lowercase
  • orderBy
  • filter
  • async
  • decimal
  • percent
  • number

Async Pipes

@Component({
    template: 
    `
        <div>
             <h1>My Component </h1>
             This component is ... {{lazydata | async}}
        </div>
    `
});


export class App{
    lazyData: Promise<string> = null;

    constructor() {
        this.lazyData =  new Promise<string>((resolve: any, reject: any) => {
                                setTimeout(()=> resolve("lazy"), 3000);
                            })        
    }
}    

Async pipe also works with Observables.

Async calls

  • Http calls return observables.
  • Observable is of a love child of Promise and collection/set
  • Observable is alias to RxJs Observable
  • Rxjs is reactive programming libraray
import {Http} from 'angular2/angular2';
import {Earthquake} from '../models/earthquake';

class EarthquakeService() {
    .
    .
    .
    
    getEarthquakeData(callback:(data: any[]) => void) {
    
      this.http.get('http://earthquake-report.com/feeds/recent-eq?json')
    
    	    .map((response: any) => {
    	        return response.json();
    	    })
    
    	    .map((jsonData: any[]) => {
    		jsonData.forEach((item) => {
    	            this.earthquakeData.push(new Earthquake(item));
    		});
    		return this.earthquakeData;
    				
    	    })
    
    	    .subscribe(
    		(data:any) => callback(this.earthquakeData), //OnNext
    		(err:any)  => console.log(err),              //OnError
    		() => console.log("call completed")          //OnComplete
    	    );
    	}
    }
}

References

  • http://blog.thoughtram.io
  • http://angularconnect.com/sessions
  • https://angular.io
  • https://disqus.com/home/forum/victorsavkinsblog
  • https://github.com/abhishek-agashe/angular2-playground

 

?

Angular 6 Advance webinars 00

By Tarun Sharma

Angular 6 Advance webinars 00

  • 642