Saturday 6 January 2018

Angular 5: Upgrading & Summary of New Features

Angular 5, code named pentagonal-donut, was just announced, and with it comes a few new features as well as a number of internal changes to make Angular apps smaller and faster to execute. In this post we’ll briefly go over some of the most important changes as well as pointers on upgrading. For more details, refer to the announcement blog post, and for in-depth details about all the changes, refer to the official changelog.

Performance

Here are some of the changes that Angular 5 includes to make your apps smaller and faster:
  • The Angular CLI v1.5 was also released today, and with it comes a build optimizer that’s enabled by default. The build optimizer performs a series of additional optimizations on builds, including better tree shaking.
  • The Angular compiler was also improved to enable faster builds and rebuilds. It now uses TypeScript transforms under the hood. Ahead of time and incremental builds are now possible when developing, using the --aot flag with the ng serve command. This should become the default in a future version of the CLI.
  • The intl and Reflect polyfills are no longer needed, which contributes to smaller bundles. Note that the Reflect polyfill is still needed in JIT mode.
  • There’s a new option, preserveWhitespaces, to remove non-significant white space characters from template code, which can further reduce your app’s final bundle size. The option is turned off by default, be it can easily be turned on for your entire app by adding a rule to your global tsconfig.json file and setting the option to a value of false:
tsconfig.json
{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": ["node_modules/@types"],
    "lib": ["es2017", "dom"]
  },
  "angularCompilerOptions": {
    "preserveWhitespaces": false
  }
}
You can also set the option granularly on a per-component basis, or override the project’s default only in specific components:
app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  preserveWhitespaces: false
})
export class AppComponent {
  // ...
}

New Features

updateOn blur or submit

A new option for form fields or entire forms, updateOn, can help with performance by telling Angular to check for validity only on blur or submit events, instead of the default change event.
For example, given a template-driven form that looks like this:
<form #newUserForm="ngForm" (ngSubmit)="onSubmit(newUserForm)">

  <label for="user-name">User Name:</label>
  <input type="text" placeholder="User name"
         required maxlength="25" id="user-name"
         [(ngModel)]="userName" name="userName">

  <button type="submit" [disabled]="!newUserForm.form.valid">
    Register
  </button>
</form>
You can now add the following to the input to have Angular check for its validity only when the input is blurred-out:
<input type="text" placeholder="User name"
      required maxlength="25" id="user-name"
      [(ngModel)]="userName" name="userName"
      [ngModelOptions]="{updateOn: 'blur'}">
You can also apply the rule for the whole form at once:
<form #newUserForm="ngForm"
      (ngSubmit)="onSubmit(newUserForm)"
      [ngFormOptions]="{updateOn: 'blur'}">
  ...
</form>

In the case of reactive forms, you’d add the option like this:
ngOnInit() {
  this.newUserForm = this.fb.group({
    userName: ['Bob', { updateOn: 'blur', validators: [Validators.required] }]
  });
}

Router Events

The Angular router now exposes a few new lifecycle events to make it easy to react to events at a more granular level. The new events are the following: ActivationStartActivationEndChildActivationStartChildActivationEndGuardsCheckEndGuardsCheckStartResolveStart and ResolveEnd.

@angular/service-worker

A new package to facilitate adding a service worker to your apps, @angular/service-worker, is now available with Angular 5. We’ll dig deeper into using it in a future post.

Upgrading

Upgrading should be a no brainer since there are very few breaking changes. The Angular team has also put together a handy tool to make upgrading as easy as possible.
Here are a few pointers that can be helpful for upgrading. This assumes that you’re upgrading from an Angular 4 app:
  • You can upgrade all your Angular packages with one command:
$ npm install @angular/{animations,common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router}@5.0.0

# or, using Yarn:
$ yarn add @angular/{animations,common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router}@5.0.0
  • Angular 5 now also depends on TypeScript 2.4.2 and RxJS 5.5.2, so you’ll want to upgrade those packages as well.
  • If you haven’t done so already, change your project’s <template> tags to <ng-template>.
  • If you’re using Flex Layout for Angular, you’ll want to make sure that you’re upgrading to the latest release (beta 10 at the time of this writing), as previous versions make use of OpaqueToken, which was removed in Angular 5.
  • If you haven’t done so already, you can start migrating your http calls over to the new HttpClient, which was introduced with Angular 4.3. The legacy Http module has now been deprecated.
  • If you’re using the datecurrency or percent pipes, there may be syntax changes needed, because Angular is now using its own implementation for those pipes instead of relying on the browser’s i18n APIs. Refer to the i18n portion of the changelog for all the details.
  • RxJS version 5.5 was also released recently, and RxJS v5.5.2 is the default for Angular 5 apps. Your code can stay exactly the same, but RxJS is moving to lettable operators to improve tree shaking and make it easier to create custom operators. Because of this, it can be a good idea to start transitioning your observable pipeline code over to the new syntax.
Here’s a quick example with the old syntax:
import { Component, OnInit } from '@angular/core';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/do';

@Component({ ... })
export class AppComponent implements OnInit {
  myObs = Observable.of('Hello', 'Alligator', 'World!');

  ngOnInit() {
    this.myObs
      .do(x => console.log('The do operator is the do operator!'))
      .filter(x => x.length > 8)
      .map(x => x.toUpperCase())
      .subscribe(x => console.log(x));
  }
}
…and the same example with the new lettable operator syntax becomes:
import { Component, OnInit } from '@angular/core';

import { of } from 'rxjs/observable/of';
import { map, filter, tap } from 'rxjs/operators';

@Component({ ... })
export class AppComponent implements OnInit {
  myObs = of('Hello', 'Alligator', 'World!');

  ngOnInit() {
    this.myObs
      .pipe(
        tap(x => console.log('The do operator is now tap!')),
        filter(x => x.length > 8),
        map(x => x.toUpperCase())
      )
      .subscribe(x => console.log(x));
  }
}
Notice how the operators can all be imported from a single import statement, and how they are now combined using the pipe method. When using lettable operators, a few operators change name. For example, the do operator becomes tap.
By default, whenever a value of a FormControl changes, Angular runs the control validation process.
So, for example, if you have an input that is bound to a form control, Angular performs the control validation process for every keystroke.

The Problem

Imagine a form with heavy validation requirements, updating on every keystroke can sometimes be too expensive.
Luckily, Angular version 5 provides a new option that improves performance by delaying form control updates until the blur or the submit event.

Reactive Forms Usage

To use it with Reactive Forms, we need to set the updateOn option to blur or submit when we instantiate a new FormControl ( the default option is change )
this.email = new FormControl(null, { updateOn: 'blur' });
Or with validators:
this.email = new FormControl(null, {
   validators: Validators.required,
   updateOn: 'blur'
});
When working with FormGroup or FormArray we can use it to set the default updateOn values for all the form's child controls. For example:
this.login = new FormGroup({
   email: new FormControl(),
   password: new FormControl()
}, { updateOn: 'submit' });
onUpdate submit example
In the above example, both the controls will be updated on submit unless one of the children explicitly specified a different updateOn value. For example:
this.login = new FormGroup({
   email: new FormControl(null, {
      validators: Validators.required,
      updateOn: 'blur'
   }),
   password: new FormControl(null, [Validators.required])
}, {updateOn: 'submit'})

Forms Module Usage

To use it with the Forms Module, we need to set the updateOn option to bluror submit in ngModelOptions. For example:
<input type="email" ngModel [ngModelOptions]="{updateOn: 'submit'}">
We can also use it to set the default updateOn values for all the form's child
controls. For example:
<form [ngFormOptions]="{updateOn: 'submit'}">
  <input name="email" ngModel type="email"> 
  <input name="password" ngModel type="email">
</form>
In the above example, both the controls will be updated on submit unless one of the children explicitly set its own updateOn value in ngModelOption. For example:
<form [ngFormOptions]="{updateOn: 'submit'}">
  <input name="email" ngModel 
         type="email" 
         [ngModelOptions]="{updateOn: 'blur'}"> 
  <input name="password" ngModel type="email">
</form>

No comments:

Post a Comment

Angular Tutorial (Update to Angular 7)

As Angular 7 has just been released a few days ago. This tutorial is updated to show you how to create an Angular 7 project and the new fe...