What's new in Angular 9

About me

  • Senior Frontend Developer @  

  • Creator of DevNote

Nutti Saelor (Lee)

Ivy is here!

Ivy

  • 3rd Generation Rendering Engine
  • Complete Rewritten
  • Tree Shaking
  • Locality

Credit: Ivy A deep dive into the heart of Angular by Martina Kraus https://t.co/Z1M3TIWzL4?amp=1

Credit:  Ivy Renderer for Dummies by Gerard Sans https://slides.com/gerardsans/components-conf-ivy-renderer#/

<div class="greeting">
  Hello, world!
</div>

View Engine

Ivy

Locality

Credit: The Post-Ivy World by Minko Gechev https://t.co/XOT3n8rQYd?amp=1

Locality

Credit: The Post-Ivy World by Minko Gechev https://t.co/XOT3n8rQYd?amp=1

Lazy Component

Credit: Angular's Future with Ivy by Manfred Steyer https://speakerdeck.com/manfredsteyer/angulars-future-with-ivy

Smaller

Smaller

Credit: Angular Connect Day 1 Keynote https://g.co/ng/ac2019

Smaller

Smaller

Faster Compilation

Faster Compilation

Angular 8.3

Faster Compilation

Angular 9.0 RC4

Improved Type Checking

Improved Type Checking

  • Basic Mode: To enable set fullTemplateTypeCheck: false
  • Full Mode: To enable set fullTemplateTypeCheck: true
  • Strict Mode: To enable set fullTemplateTypeCheck: true and strictTemplates: true

Improved Type Checking

// tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    ...
  },
  "angularCompilerOptions": {
    "fullTemplateTypeCheck": true,
    "strictTemplates": true
  }
}

Improved Type Checking

Basic Mode

  • Validate only top-level expression
  • Don't check embedded view (*ngIf *ngFor ng-template)
  • Don't figure out the types of #ref, results of pipes, type of event

Improved Type Checking

Full Mode

  • More aggressive in its type-checking within templates ex. Embedded view are checked, pipes have correct return type, Local references(Directive/Pipe) have correct type
  • Local references to DOM, $event object still have type any

Improved Type Checking

Strict Mode

  • Verifies that component/directive bindings are assignable to their @Input()s
  • Infers the correct type of components/directives, including generics
  • Infers the correct type of $event
  • Infers the correct type of local references to DOM element

Improved Type Checking

interface User {
  name: string;
  address: {
    city: string;
    state: string;
  }
}
<div *ngFor="let user of users">
  <h2>{{config.title}}</h2>
  <span>City: {{user.address.city}}</span>
</div>

How to update?

How to update?

Credit: The Post-Ivy World by Minko Gechev https://t.co/XOT3n8rQYd?amp=1

Backward Compatible

Backward Compatible

Credit: The Post-Ivy World by Minko Gechev https://t.co/XOT3n8rQYd?amp=1

Backward Compatible

Credit: The Post-Ivy World by Minko Gechev https://t.co/XOT3n8rQYd?amp=1

Backward Compatible

Credit: The Post-Ivy World by Minko Gechev https://t.co/XOT3n8rQYd?amp=1

Backward Compatible

Opting out of Ivy

// tsconfig.app.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": []
  },
  "files": [ ...],
  "include": [
    "src/**/*.d.ts"
  ],
  "angularCompilerOptions": {
    "enableIvy": false
  }
}

Ivy Compatible Guide

Other updates

Clipboard CDK

<button cdkCopyToClipboard="👋 You copied me!">Click to copy</button>
constructor(private clipboard: Clipboard) {}

copyId(id: string) {
  this.clipboard.copy(id)
}

Google Maps Component

<google-map
  height="500px"
  width="100%"
  [zoom]="zoom"
  [center]="center"
  [options]="options"
  (mapClick)="click($event)"
>
  <map-marker
    #markerElem
    *ngFor="let marker of markers"
    [position]="marker.position"
    [label]="marker.label"
    [title]="marker.title"
    [options]="marker.options"
    (mapClick)="openInfo(markerElem, marker.info)"
  >
  </map-marker>

  <map-info-window>{{ infoContent }}</map-info-window>
</google-map>

Default Value for static flag

@ViewChild(ChildDirective) child: ChildDirective;

@ViewChild(ChildDirective, { static: false }) child: ChildDirective; // similar to above code

TypeScript 3.6 Support

Deprecated

Deprecated

Replace TestBed.get with TestBed.inject

TestBed.get(ChangeDetectorRef) // returns any

TestBed.inject(ChangeDetectorRef) // returns ChangeDetectorRef

No more entryComponents

@NgModule({
  imports: [MatDialogModule],
  declarations: [AppComponent, ExampleDialogComponent],
  entryComponents: [ExampleDialogComponent],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Future with Ivy

*with experimental API

Higher Order Component

Credit: Angular's Future with Ivy by Manfred Steyer https://speakerdeck.com/manfredsteyer/angulars-future-with-ivy

Higher Order Component

const routes: Routes = [
  {
    path: 'comic/:comicId',
    component: withRoute(ComicComponent)
  }
];

Optional NgModule

import {Component, Input, ɵrenderComponent as renderComponent, Pipe, ɵmarkDirty as markDirty} from '@angular/core';
import '@angular/compiler';

@Component({...})
class ChildComponent { ... }

@Pipe({ name: 'capitalize' })
class CapitalizePipe { ... }

@Component({
  selector: 'app-cmp',
  template: '<zippy title="Toggle">{{ label | capitalize }}</zippy>',
  deps: [ChildComponent, CapitalizePipe]
})
class AppComponent {
  label = 'hello world';
}

renderComponent(AppComponent);

Credit: angular-ivy-demo by Minko Gechev https://github.com/mgechev/angular-ivy-demo

Zone less Application

import {Component, Input, ɵrenderComponent as renderComponent, Pipe, ɵmarkDirty as markDirty} from '@angular/core';
import '@angular/compiler';

@Component({
  selector: 'zippy',
  template: `
    <button (click)="toggle()">
      {{title}}
    </button>
    <div [hidden]="!show">
      <ng-content></ng-content>
    </div>
  `,
})
class ChildComponent {
  @Input() title: string;
  show = false;
  toggle() {
    this.show = !this.show;
    markDirty(this);
  }
}

...

Credit: angular-ivy-demo by Minko Gechev https://github.com/mgechev/angular-ivy-demo

Q&A

Thank you!

Made with Slides.com