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: ActivationStart, ActivationEnd, ChildActivationStart, ChildActivationEnd, GuardsCheckEnd, GuardsCheckStart, ResolveStart 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 date, currency 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.

🎢 With this, you should now be ready to leap into Angular 5 and benefit from the resulting faster and smaller apps.

  Tweet It
✖ Clear

🕵 Search Results

🔎 Searching...