developers

Angular 5 Release: What’s New?

Angular 5 brings some new features to the popular JavaScript framework for building mobile, desktop and web applications. Learn what's new in Angular!

Nov 14, 20177 min read


TL;DR: Angular is an all-encompassing JavaScript framework that is frequently used by developers all over the world for building web, desktop, and mobile applications. In this article, I'll cover the new features in Angular 5 and several other changes and deprecations.


Angular is built and maintained by Google.. It is a platform that combines declarative templates, dependency injection, end to end tooling, and integrated best practices to solve development challenges. Web platforms such as Google Adwords, Google Fiber, Adsense, and Winc use Angular to build their user interfaces.

Angular 5 was announced to the world on November 1, 2017. The previous Angular version was 4.4.0. This release focused on making Angular smaller and faster to use. Let's go through the major changes in version 5.

1. Http Deprecated, HttpClient Here to Stay

Before version 4.3, the

@angular/http
module was used for making HTTP requests in Angular applications. The Angular team has now deprecated
Http
in version 5. The
HttpClient
API from
@angular/common/http
package that shipped in version 4.3 is now recommended for use in all apps. The
HttpClient
API features include:

  • Typed, synchronous response body access, including support for JSON body types.
  • JSON is an assumed default and no longer needs to be explicitly parsed.
  • Interceptors allow middleware logic to be inserted into the pipeline.
  • Immutable request/response objects.
  • Progress events for both request upload and response download.
  • Post-request verification & flush based testing framework.
import { HttpClientModule } from '@angular/common/http';

2. Support for Multiple Export Alias in Angular 5

In Angular 5, you can now give multiple names to your components and directives while exporting. Exporting a component with multiple names can help your users migrate without breaking changes.

Exporting a component with multiple names can help your users migrate without breaking changes.

Tweet This

Example Usage:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  exportAs:'dashboard, logBoard'
})
export class AppComponent {
  title = 'app';
}

3. Internationalized Number, Date, and Currency Pipes

Angular 5 ships with new number, date, and currency pipes that increase standardization across browsers and eliminate the need for i18n polyfills. The pipes rely on the CLDR to provide extensive locale support and configurations for any locales you want to support. To use the old pipes, you will have to import the

DeprecatedI18NPipesModule
after the
CommonModule
.

  import { NgModule } from '@angular/core';
  import { CommonModule, DeprecatedI18NPipesModule } from '@angular/common';

  @NgModule({
    imports: [
      CommonModule,
      // import deprecated module after
      DeprecatedI18NPipesModule
    ]
  })
  export class AppModule { }

4. Improved Decorator Support in Angular 5

Angular 5 now supports expression lowering in decorators for lambdas, and the value of

useValue
,
useFactory
, and
data
in object literals. Furthermore, a lambda can be used instead of a named function like so:

In Angular 5

  Component({
    provider: [{provide: 'token', useFactory: () => null}]
  })
  export class MyClass {}

Before Angular 5

  Component({
    provider: [{provide: 'token', useValue: calculated()}]
  })
  export class MyClass {}

5. Build Optimization

The Angular team focused on making Angular 5 faster, smaller and easier to use. In Angular 5, production builds created with the Angular CLI will now apply the build optimizer by default. The build optimizer removes Angular decorators from your app's runtime codes thereby reducing the size of your bundle and increasing the boot speed of your application. In addition, the build optimizer removes part of your application that is not needed during runtime via tree-shaking. This action leads to a decreased bundle size, and faster application speed.

In Angular 5, production builds created with the Angular CLI will now apply the build optimizer by default.

Tweet This

6. Angular Universal Transfer API

The Angular Universal team has added Domino to the

platform-server
. This simply means more DOM manipulations can happen out of the box within server-side contexts.

Furthermore, two modules,

ServerTransferStateModule
and
BrowserTransferModule
have been added to Angular Universal. These modules allow you to generate information as part of your rendering with platform-server and then transfer it to the client side to avoid re-generation of the same information. In summary, it transfers state from the server which means developers do not need to make a second HTTP request once the application makes it to the client.

7. Faster Compiler in Angular 5

A lot of improvements have been made to the Angular compiler to make it faster. The Angular compiler now leverages TypeScript transforms. You can take advantage of it by running:

ng serve --aot

Angular.io was used as a case study and the compiler pipeline saved 95% of the build time when an incremental AOT build was performed on it.

Note: TypeScript transforms are a new feature introduced as part of TypeScript 2.3, that allows hooking into the standard TypeScript compilation pipeline.

8. Forms Validation in Angular 5

In Angular 5, forms now have the ability to decide when the validity and value of a field or form are updated via on

blur
or on
submit
, instead of every input event.

Example Usage

  <input name="nickName" ngModel [ngModelOptions]="{updateOn: 'blur'}">

Another Example

  <form [ngFormOptions]="{updateOn: 'submit'}">

In the case of Reactive forms, you can add the option like so:

ngOnInit() {
  this.newUserForm = this.fb.group({
    userName: ['Bob', { updateOn: 'blur', validators: [Validators.required] }]
  });
}

9. Animations in Angular 5

In Angular 5, we have two new transition aliases,

:increment
and
:decrement
.

...
animations: [
  trigger('bannerAnimation', [
   transition(":increment", group([
     query(':enter', [
       style({ left: '100%' }),
       animate('0.5s ease-out', style('*'))
     ]),
     query(':leave', [
       animate('0.5s ease-out', style({ left: '-100%' }))
     ])
   ])),
   transition(":decrement", group([
     query(':enter', [
       style({ left: '-100%' }),
       animate('0.5s ease-out', style('*'))
     ]),
     query(':leave', [
       animate('0.5s ease-out', style({ left: '100%' }))
     ])
   ])),
 ])
]

Animation queries now support negative limits, in which case elements are matched from the end rather than from the beginning like so:

...
animations: [
 trigger(
   'myAnimation',
   [
     transition(
         '* => go',
         [
           query(
               '.item',
               [
                 style({opacity: 0}),
                 animate('1s', style({opacity: 1})),
               ],
               {limit: -3}),
        ]),
   ]),
]
...

10. New Router Lifecycle Events in Angular 5

Some new lifecycle events have been added to the router. The events are

GuardsCheckStart
,
ChildActivationStart
,
ActivationStart
,
GuardsCheckEnd
,
ResolveStart
,
ResolveEnd
,
ActivationEnd
, and
ChildActivationEnd
. With these events, developers can track the cycle of the router from the start of running guards through to completion of activation.

Furthermore, you can now configure the router to reload a page when it receives a request to navigate to the same URL.

providers: [
  // ...
  RouterModule.forRoot(routes, {
    onSameUrlNavigation: 'reload'
  })
]

11. Better Support for Service Workers in Angular 5

In Angular 5, we have better support for service workers via the @angular/service-worker package. The service worker package is a conceptual derivative of the

@angular/service-worker
package that was maintained at github.com/angular/mobile-toolkit, but has been rewritten to support use-cases across a much wider variety of applications.

Note: Right now you will have to manually integrate the package because it's not fully integrated with the CLI v1.5 yet. It is available as beta in version 1.6 of the CLI.

Deprecations and Other Updates

  • NgFor
    has been removed as it was deprecated since v4. Use
    NgForOf
    instead. This does not impact the use of
    *ngFor
    in your templates.
  • The compiler option
    enableLegacyTemplate
    is now disabled by default as the
    <template>
    element was deprecated since v4. Use
    <ng-template>
    instead. The option
    enableLegacyTemplate
    and the
    <template>
    element will both be removed in Angular v6.
  • The method
    ngGetContentSelectors()
    has been removed as it was deprecated since v4. Use
    ComponentFactory.ngContentSelectors
    instead.
  • ReflectiveInjector
    is now deprecated. Use
    Injector.create
    as a replacement.
  • NgProbeToken
    has been removed from
    @angular/platform-browser
    as it was deprecated since v4. Import it from
    @angular/core
    instead.

Check out other Angular 5 updates here.

Upgrading to Angular 5

The Angular team built a nifty tool to make upgrading as easy as possible.

Angular 5 Upgrade Angular 5 upgrade tool

Aside: Authenticate an Angular App with Auth0

By integrating Auth0 in your Angular application, you will be able to manage user identities, including password resets, creating, provisioning, blocking, and deleting users. It requires just a few steps.

Auth0 login screen

Set up an Auth0 application

First, sign up for a free account here. Then, set up an Auth0 application with the following steps:

  1. Go to your Applications section of the Auth0 Dashboard and click the "Create Application" button.
  2. Name your new app and select "Single Page Web Applications" as the application type.
  3. In the Settings for your new Auth0 app, add
    http://localhost:4200
    to the Allowed Callback URLs, Allowed Web Origins, and Allowed Logout URLs. Click the "Save Changes" button.
  4. If you'd like, you can set up some social connections. You can then enable them for your app in the Application options under the Connections tab. The example shown in the screenshot above uses username/password database, Facebook, Google, and Twitter.

Note: Set up your own social keys and do not leave social connections set to use Auth0 dev keys, or you will encounter issues with token renewal.

Add dependencies and configure

In the root folder of your Angular project, install the

auth0-spa-js
library by typing the following command in a terminal window:

npm install @auth0/auth0-spa-js

Then, edit the

environment.ts
file in the
src/environments
folder and add the
CLIENT_DOMAIN
and
CLIENT_ID
keys as follows:

// src/environments/environment.ts

export const environment = {
  production: false,
  auth: {
    CLIENT_DOMAIN: 'YOUR_DOMAIN',
    CLIENT_ID: 'YOUR_CLIENT_ID',
  },
};

export const config = {};

Replace the

YOUR_DOMAIN
and
YOUR_CLIENT_ID
placeholders with the actual values for the domain and client id you found in your Auth0 Dashboard.

Add the authentication service

Authentication logic in your Angular application is handled with an

AuthService
authentication service. So, use Angular CLI to generate this new service by running the following command:

ng generate service auth

Now, open the

src/app/auth.service.ts
file and replace its content with the following:

//src/app/auth.service.ts

import { Injectable } from '@angular/core';
import createAuth0Client from '@auth0/auth0-spa-js';
import Auth0Client from '@auth0/auth0-spa-js/dist/typings/Auth0Client';
import {
  from,
  of,
  Observable,
  BehaviorSubject,
  combineLatest,
  throwError,
} from 'rxjs';
import { tap, catchError, concatMap, shareReplay } from 'rxjs/operators';
import { Router } from '@angular/router';
import { environment } from './../environments/environment';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  // Create an observable of Auth0 instance of client
  auth0Client$ = (from(
    createAuth0Client({
      domain: environment.auth.CLIENT_DOMAIN,
      client_id: environment.auth.CLIENT_ID,
      redirect_uri: `${window.location.origin}`,
    }),
  ) as Observable<Auth0Client>).pipe(
    shareReplay(1), // Every subscription receives the same shared value
    catchError((err) => throwError(err)),
  );
  // Define observables for SDK methods that return promises by default
  // For each Auth0 SDK method, first ensure the client instance is ready
  // concatMap: Using the client instance, call SDK method; SDK returns a promise
  // from: Convert that resulting promise into an observable
  isAuthenticated$ = this.auth0Client$.pipe(
    concatMap((client: Auth0Client) => from(client.isAuthenticated())),
    tap((res) => (this.loggedIn = res)),
  );
  handleRedirectCallback$ = this.auth0Client$.pipe(
    concatMap((client: Auth0Client) => from(client.handleRedirectCallback())),
  );
  // Create subject and public observable of user profile data
  private userProfileSubject$ = new BehaviorSubject<any>(null);
  userProfile$ = this.userProfileSubject$.asObservable();
  // Create a local property for login status
  loggedIn: boolean = null;

  constructor(private router: Router) {
    // On initial load, check authentication state with authorization server
    // Set up local auth streams if user is already authenticated
    this.localAuthSetup();
    // Handle redirect from Auth0 login
    this.handleAuthCallback();
  }

  // When calling, options can be passed if desired
  // https://auth0.github.io/auth0-spa-js/classes/auth0client.html#getuser
  getUser$(options?): Observable<any> {
    return this.auth0Client$.pipe(
      concatMap((client: Auth0Client) => from(client.getUser(options))),
      tap((user) => this.userProfileSubject$.next(user)),
    );
  }

  private localAuthSetup() {
    // This should only be called on app initialization
    // Set up local authentication streams
    const checkAuth$ = this.isAuthenticated$.pipe(
      concatMap((loggedIn: boolean) => {
        if (loggedIn) {
          // If authenticated, get user and set in app
          // NOTE: you could pass options here if needed
          return this.getUser$();
        }
        // If not authenticated, return stream that emits 'false'
        return of(loggedIn);
      }),
    );
    checkAuth$.subscribe();
  }

  login(redirectPath: string = '/') {
    // A desired redirect path can be passed to login method
    // (e.g., from a route guard)
    // Ensure Auth0 client instance exists
    this.auth0Client$.subscribe((client: Auth0Client) => {
      // Call method to log in
      client.loginWithRedirect({
        redirect_uri: `${window.location.origin}`,
        appState: { target: redirectPath },
      });
    });
  }

  private handleAuthCallback() {
    // Call when app reloads after user logs in with Auth0
    const params = window.location.search;
    if (params.includes('code=') && params.includes('state=')) {
      let targetRoute: string; // Path to redirect to after login processed
      const authComplete$ = this.handleRedirectCallback$.pipe(
        // Have client, now call method to handle auth callback redirect
        tap((cbRes) => {
          // Get and set target redirect route from callback results
          targetRoute =
            cbRes.appState && cbRes.appState.target
              ? cbRes.appState.target
              : '/';
        }),
        concatMap(() => {
          // Redirect callback complete; get user and login status
          return combineLatest([this.getUser$(), this.isAuthenticated$]);
        }),
      );
      // Subscribe to authentication completion observable
      // Response will be an array of user and login status
      authComplete$.subscribe(([user, loggedIn]) => {
        // Redirect to target route after callback processing
        this.router.navigate([targetRoute]);
      });
    }
  }

  logout() {
    // Ensure Auth0 client instance exists
    this.auth0Client$.subscribe((client: Auth0Client) => {
      // Call method to log out
      client.logout({
        client_id: environment.auth.CLIENT_ID,
        returnTo: `${window.location.origin}`,
      });
    });
  }
}

This service provides the properties and methods necessary to manage authentication across your Angular application.

Add the login and logout buttons

To add a new component that allows you to authenticate with Auth0, run the following command in a terminal window:

ng generate component login-button

Open the

src/app/login-button/login-button.component.ts
file and replace its content with the following:

//src/app/login-button/login-button.component.ts

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../auth.service';

@Component({
  selector: 'app-login-button',
  templateUrl: './login-button.component.html',
  styleUrls: ['./login-button.component.css'],
})
export class LoginButtonComponent implements OnInit {
  constructor(public auth: AuthService) {}

  ngOnInit() {}
}

Next, define the component's UI by replacing the content of the

src/app/login-button/login-button.component.html
with the following markup:

<!-- src/app/login-button/login-button.component.html -->
<div>
  <button (click)="auth.login()" *ngIf="!auth.loggedIn">Log In</button>
  <button (click)="auth.logout()" *ngIf="auth.loggedIn">Log Out</button>
</div>

Finally, put the

<app-login-button></app-login-button>
tag within the
src/app/app.component.html
file, wherever you want the component to appear.

Your Angular application is ready to authenticate with Auth0!

Check out the Angular Quickstart to learn more about integrating Auth0 with Angular applications.

Conclusion

Angular 5 came loaded with new features and significant improvements. It is smaller and faster. I am proud of what the Angular team achieved with this release.

Have you switched to Angular 5 yet? What are your thoughts? Did you notice any significant improvement? Let me know in the comments section! 😊