Professional Documents
Culture Documents
Angular 5 Companion Guide
Angular 5 Companion Guide
John Niedzwiecki II
Angular 5 Companion Guide
Angular has grown and evolved over the Things you will learn:
past couple of years. The Angular team
adopted semantic versioning with a
six-month major release cycle to create • Get up to date with the new features
Angular 5
predictable releases of improvements introduced in Angular 5
and features to give developers the tools
they need to create the best applications.
These releases keep the libraries, tools, and • Keep up with the latest updates
practices the best they can be. and benefits from TypeScript 2.x
Companion Guide
Divided into three parts, this short guide
will help Angular developers explore the • Make your life easier by knowing how
core changes and new features introduced to migrate your Angular code to the
in versions 4 and 5, as well as a glimpse into latest version
the future at what's to come in
Angular 6. While this book is primarily
about Angular 5, it also covers some of • Explore how Angular Universal helps
the great features added during the minor developers perform server-side
releases of version 4. If you’re coming rendering
from Angular 2, or want the highlights of
everything added during past releases, this
is a great starting point. • Learn about Service workers and how
they help in building progressive web
Next, explore version 5 feature changes
applications
and additions that will allow developers
to build smart, progressive web apps with
less code. The aim is to provide developers • Take a look into the future at what to
with the information needed to hit the expect from Angular 6
ground running with new features, changes Get up and running with the latest features of Angular 5
in the Typescript ecosystem, and migrating
to different versions. By the end of the • Explore the performance
book, you will have gained the knowledge improvements made to the Angular
required to dive straight into Angular 5 ecosystem
and successfully integrate it into your
projects.
$ 99.99 US
£ 99.99 UK
John Niedzwiecki II
BIRMINGHAM - MUMBAI
Angular 5 Companion Guide
Copyright © 2017 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form
or by any means, without the prior written permission of the publisher, except in the case of brief quotations
embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented.
However, the information contained in this book is sold without warranty, either express or implied. Neither the
author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to
be caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products
mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy
of this information.
ISBN 978-1-78883-856-6
www.packtpub.com
mapt.io
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as
well as industry leading tools to help you plan your personal development and advance
your career. For more information please visit our website.
Why subscribe?
Spend less time learning and more time coding with practical eBooks and Videos
from over 3,500 industry professionals
PacktPub.com
Did you know that Packt offers eBook versions of every book published, with PDF and
ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a
print book customer, you are entitled to a discount on the eBook copy. Get in touch with us
at [email protected] for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a
range of free newsletters and receive exclusive discounts and offers on Packt books and
eBooks.
Contributors
He has spoken at a number of conferences, including AngularMix. You can find him out
and about in northern Virginia, rambling on his blog, hanging around on Twitter, and if
he’s lucky, at his happy place of Walt Disney World.
Packt is Searching for Authors Like You
If you’re interested in becoming an author for Packt please visit http://authors.packtpub.
com/ and apply today. We have worked with thousands of developers and tech
professionals, just like you, to help them share their insight with the global tech community.
You can make a general application, apply for a specific hot topic that we are searching for
an author for, or submit your own idea.
Table of Contents
Part 1: What did I miss in Angular 4? 1
StrictNullChecks 17
Support for mixin classes 17
Better checking for null/undefined in operands of expressions 18
Generators and iteration for ES5/ES3 18
Async iteration 19
Master --strict option 19
Check for errors in .js files 20
Chapter 3: Migrating to Version 4 21
Animations 25
Router events 26
Pipes 27
Watch mode 28
Lazy loading 29
Material Design 29
Service worker package 29
Strict Injectable checking 32
Performance improvement 33
Chapter 5: New Features in Typescript 2.4 34
String enums 34
Improved inference for generics 34
Weak type detection 35
Chapter 6: Migrating to Version 5 36
[ ii ]
Part 1
Introduction of ng-template
The Angular team introduced the <ng-template> element. This change was introduced in
order to operate better with web components that may use the standard <template> tag by
avoiding any conflicts over the use of this tag by Angular. This is a small change, but sees
the deprecation of the template tag and attribute, which will result in a deprecation warning
while running 4.x in development mode:
<ng-template #awesome>
My <span class="awesome">awesome</span> template content!
</ng-template>
[3]
Changes in Version 4.x Chapter ŗ
First, the new HttpClient automatically maps responses to JSON by default. This keeps
you from needing to call response.json() on every request. This value is configurable for
cases when mapping to JSON may not be appropriate, such as an API with a plain text
response:
// old way
http.get(url)
.map(response => response.json() as Items)
.subscribe( ... );
The second change is the inclusion of the HttpInterceptor interface. If you've worked
with interceptors in Angular 1.x, you'll be familiar with them. Interceptors allow you to
intercept requests and responses to perform additional functionality or modify them
globally. You can modify the outgoing request or transform the response event stream.
To create an interceptor, you must declare a class that implements the HttpInterceptor
interface. The following code creates an authorization interceptor. Its purpose is to add an
authorization header to send with every request. We include an authorization service that
will return us the value to add. For example, you could be using JWT to manage
authentication, and the service would return the token from the getAuthValue() call:
import { Injectable } from '@angular/core';
import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
[4]
Changes in Version 4.x Chapter ŗ
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(
private auth: AuthService
) { }
/*
* Intercept function to get request before it is made.
* Gets request and adds header for authorization.
* @returns Observable from modified request.
*/
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
// get request and add header
request = request.clone({
setHeaders: {
Authorization: `Bearer ${this.auth.getAuthValue()}`
}
});
return next.handle(request);
}
}
To use your interceptor, it needs to be added in the providers in the application's module
to the HTTP_INTERCEPTORS array:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './../auth/auth.interceptor';
@NgModule({
bootstrap: [ AppComponent ],
imports: [ ... ],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
]
})
export class AppModule { }
[5]
Changes in Version 4.x Chapter ŗ
You can also intercept the response before it is returned. The setup is the same for the
interceptor, but we add our logic to the next.handle portion of the code before it is run. In
the following code, we'll create an interceptor to help us capture several 4xx error codes:
import { Injectable } from '@angular/core';
import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
constructor() { }
The new HttpClient also allows you to track the progress of uploads and downloads for
when you're working with transfers of large amounts of data. You can configure an instance
of HttpRequest with the reportProgress option to enable progress events:
const uploadRequest = new HttpRequest(
'POST',
'/upload/file',
file,
{
[6]
Changes in Version 4.x Chapter ŗ
reportProgress: true
}
);
http.request(uploadRequest).subscribe(event => {
// Get upload progress event from raw event stream
if (event.type === HttpEventType.UploadProgress) {
// Compute percentage
const percentDone = Math.round(100 * event.loaded / event.total);
console.log(`File is ${percentDone}% uploaded.`);
} else if (event instanceof HttpResponse) {
console.log('File is done uploading!');
}
});
In addition to their own module, the minor release of Angular 4 has seen a large number of
improvements and additions to animations. Let's take a look at some of these changes.
The first feature added is the ability to configure options and set input variables within
animations. This allows you to configure and override options for the various step-based
animation methods. The two options are options.delay and options.params. The first
option, options.delay, does exactly what it says-it allows you to delay the start of the
animation. This does not support percentages or negative values, though negative values
are planned for a future release. The second option, options.params, is for adding input
parameters. These inputs allow you to pass in data to be used for style properties and
timing values within an animation sequence. Any key/value pair provided through
options.params can be used with {{ binding }} to access the value:
[7]
Changes in Version 4.x Chapter ŗ
], {
duration: "5s",
endOpacity: "1"
})
Both of these options can be set by a new method parameter (as seen in the preceding code
example) or can be passed into an animation binding value. It should be noted that these
values do not update once an animation starts. It will evaluate the values at the start to
build the animation and then, it will not change while the animation is executing.
The second feature added provides the ability to create a reusable animation. The
animation() helper method lets you define and package animations that can be used
elsewhere, while supporting the previously mentioned inputs. The following code will
create a reusable animation that also accepts inputs for customization of the animation:
import {animation, style, animate} from "@angular/animations";
You've now created a fadeAnimation variable that can be used throughout our
application, fully definable by input parameters. We've also defined the default values for
the inputs. To use the animation, you invoke it with the useAnimation() function and
specify the input parameters:
import {useAnimation, transition} from "@angular/animations";
import {fadeAnimation} from "./animations";
[8]
Changes in Version 4.x Chapter ŗ
The third feature added gives the ability to create really powerful animations. The query()
function allows you to select child elements and animate them separately from each other in
parallel within the element with the animation trigger. This allows you to create
multielement animations triggered together:
animations: [
trigger('groupAnimation', [
transition('* => *', group([
// start elements hidden
query('*', style({ opacity: 0 })),
The provided code does several things. The key part is the query selector. It allows for
several values to be used. The first values you can use are regular CSS selectors that can
return one or more items matching the selector string, as seen with div.groupHeader.
Additionally, query can use query(':enter') for new nodes and query(':leave') for
nodes marked to be removed, within the container. Additionally, query finds elements with
animation triggers through query('@triggerName') or all items with animation triggers
with query('@*'). Query can find all elements that are currently animating using
query(':animating'). Finally, the container element itself can be selected with
query(':self'), which is useful if you want the container itself to have animation in
addition to child elements selected through queries.
The query function will throw an error if it doesn't find any elements, by default. You can
override this with the query option of { optional: true }. In addition, you can limit the
number of elements to be selected by setting the limit option value.
[9]
Changes in Version 4.x Chapter ŗ
The query function is powerful for allowing us to do multiple animations in one. It gets
even more powerful when we pair it with the new stagger() animation helper function.
Stagger allows you to stagger animations for elements, spacing them out so that the
animations start with a gap of time in between. Let's create a staggered animation for a list
with an ngFor that has a container wrapped around it:
<div [@listAnimation]="items.length">
<div *ngFor="let item of items">
{{ item }}
</div>
</div>
You can query those inner elements of our divs added with the ngFor and animate them as
they are added, but stagger them so that they start their animation with a gap in between:
trigger('listAnimation', [
transition('* => *', [
// starts elements off to side
query(':enter', style({ transform: 'translateX(-100%)' })),
// starts animations with 100ms in between
query(':enter', stagger('100ms', [
animate('1s', style({ transform: 'translateX(0)' }))
])
])
])
The next feature allows you to take animations one step further and apply them to routes.
We can have an animation activated on the route change and animate the components that
come and leave the router-outlet.
To begin, we need to wrap our outlet in an element to trigger our animation, as we cannot
add the trigger directly to the router-outlet because of how it works. We also need to get
a hold of the details of the route switching in and out through a function and a route local
variable:
<div [@routeAnimation]="getRouteAnimation(route)">
<router-outlet #route="outlet"></router-outlet>
</div>
[ 10 ]
Changes in Version 4.x Chapter ŗ
Next, our component must define the getRouteAnimation function. This will define the
state value to be used by the routeAnimation animation. The animation itself will fade in
the new route and fade out the old. By using a group, we can keep the animations
simultaneous:
import { Component} from '@angular/core';
import {
animate,
query,
state,
style,
transition,
trigger
} from '@angular/animations';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
animations: [
trigger('routeAnimation', [
transition('* <=> *', [
group([
// fade in new route
query(':enter', [
style({ opacity: 0 }),
animate('500ms', style({ opacity: 1 }))
]),
// fade fade out old route
query(':leave', [
animate('500ms', style({ opacity: 0 }))
])
])
])
])
]
})
export class AppComponent {
getRouteAnimation(outlet) {
return outlet.activatedRouteData.animation
}
}
[ 11 ]
Changes in Version 4.x Chapter ŗ
You can see that the getRouteAnimation function takes in the outlet and returns a string
value for the state of the animation. This will be determined by custom data of the current
active route, which we must then define in our routing:
const routes: Routes = [
{
path: 'home',
component: HomeComponent,
data: {
animation: 'home'
}
},
{
path: 'list',
component: ListComponent,
data: {
animation: 'list'
}
}
];
In providing these values, you can use them to define custom animations between two
particular routes, as opposed to our example that does one animation between all routes:
// home to list
transition('home => list', [
// animation 1
]),
// list back to home
transition('list => home', [
// animation 2
])
The final feature gives you the power to programmatically build animations through the
AnimationBuilder service. This service allows you to create and define animations within
a component. However, it requires you to define more aspects of the controls for the
animation. Normally, triggers do a lot of the work for you to track the state of animations,
which you will need to define yourself if using the AnimationBuilder.
[ 12 ]
Changes in Version 4.x Chapter ŗ
To build an animation in a component, there are several key pieces. First, you build the
animation with factory = this.animationBuilder.build( ... ). Second, you
create an AnimationPlayer from your builder with player =
factory.create(someElement). Third, you tell the player to play with player.play().
Let's see a full example of a component to create a loading bar that animates to the width
provided by an input:
import {
AnimationBuilder,
AnimationPlayer
} from '@angular/animations';
@Component({
selector: 'loading-bar',
template: `<div class="loading" #loading></div>`
})
class LoadingBarComponent {
@ViewChild('loading')
public loading;
@Input('percentage')
set percentage(per: number) {
this._percentage = p;
this.startLoading();
}
get percentage() {
return this._percentage;
}
constructor(
private animationBuilder: AnimationBuilder
) { }
startLoading() {
// stop animation if ongoing
if(this.player) {
this.player.destroy();
}
// build animation
const loadingAnimation = this.animationBuilder.build([
style({ width: 0 }),
animate('1s', style({ width: `${this._percentage}%` }))
]);
[ 13 ]
Changes in Version 4.x Chapter ŗ
To use this component with the built animation, you use it like any other component and
provide it the input value of the percentage:
<loading-bar [percentage]="percentage"></loading-bar>
Source maps
The Angular team has also made additions to the tools to make life easier for developers.
One of the features added was to create source maps for templates. This addition adds
value when debugging during development. This was added to the template compiler,
providing more contextual information when debugging in the browser, or from crash
reports, than previously available.
[ 14 ]
Changes in Version 4.x Chapter ŗ
Angular Universal
Angular Universal is the project created to handle running Angular on the server and
provide server-side rendering. With the release of version 4.0, this project was adopted by
the Angular core team and brought into the official code base. This brought the code into
platform-server, making it readily available and integrated. The topic of server-side
rendering is too large to be covered over here, but it's important to know that its inclusion
into the core code base makes it easier to be used and integrated into your project.
Angular CLI
With the 4.0 release, much like Angular Universal, the Angular CLI was officially brought
into the Angular project. The CLI reached its 1.0.0 release alongside the Angular version 4.0
release and has continued to progress. The improvements include the AoT compilation that
will be discussed under the New view Engine section, upgrades to webpack that bundles the
code, improved error messages, and all the scaffolding it can create for you. If you haven't
been using the CLI for your Angular project, you should start using it. Get started with it
and create your first new project using the following code:
ng new PROJECT-NAME
[ 15 ]
Changes in Version 4.x Chapter ŗ
In addition, the Angular team improved performance by lessening the amount of work
done by browser garbage collectors. The best part is that this comes with no work to you
just using the Angular-CLI.
[ 16 ]
Keeping up with TypeScript
2
One of the great features of Angular is working in TypeScript. The benefits of TypeScript
are numerous. Throughout the development of Angular versions, the Angular team has
been keeping up with the latest updates and benefits from TypeScript. With the 4.0 release,
the Angular team updated for support of TypeScript 2.1. During the 4.1 release, the team
updated with support for TypeScript versions 2.2 and 2.3. This chapter will look at some of
the additions to TypeScript that can benefit the code you write in your Angular application.
StrictNullChecks
With the 4.0 release of Angular, in addition to updating to TypeScript 2.1, the team also
updated the Angular code base to be compliant with TypeScript's StrictNullChecks
setting. This switches the TypeScript compiler to a strict null checking mode, where null
and undefined values are not in the domain of every data type. The goal is to write safer
code. The TypeScript compiler will catch code trying to use null values that are not
explicitly stated to be nullable and catch the "possibly null" case. For example, the compiler
will show an error if you try to access a property of an object that may be undefined, such
as an optional parameter. This update allows you to enable to this flag (-
strictNullChecks) in your own application without the Angular code base throwing
errors.
Finally, if we use that class, we get the foo() defined in the mixin:
let cc = new CustomClass();
cc.foo(); // logs 'foo called in CustomMixin'
[ 18 ]
Keeping up with TypeScript Chapter Ř
Generators are functions used to compute results using an Iterator and the yield keyword.
TypeScript 2.3 added full support for generators and iterators for targeting ES3 and ES5
with the use of the --downlevelIteration flag. When the flag is used, the compiler uses
a new type check that will adjust the calls on an iterated object with
[Symbol.iterator]() or create a synthetic array iterator if it cannot. Enabling this flag
will also allow for..of, array destructuring, and spread elements to function in ES5/ES3.
Async iteration
TypeScript 2.3 also adds support for async iterators and generators to align with the
current TC39 proposal. Part of what makes TypeScript great is adding support for the latest
in JavaScript. An AsyncIterator is similar to an Iterator; however, the next, return, and
throw methods return a Promise instead of an actual value result:
interface AsyncIterator<T> {
next(value?: any): Promise<IteratorResult<T>>;
return?(value?: any): Promise<IteratorResult<T>>;
throw?(e?: any): Promise<IteratorResult<T>>;
}
[ 19 ]
Keeping up with TypeScript Chapter Ř
[ 20 ]
Migrating to Version 4
3
Migrating to Angular 4 was intended to be simple. The goal that was set out from the
beginning of version 2 and semantic versioning was to keep version-to-version upgrades
simple. Migrating to version 4 of Angular kept true to this vision, while providing a lot of
extra great features.
To migrate to version 4, the first update you need to make is to update your dependencies.
This update is simple; in doing this, you will need to add the Animations module, if you are
already using them in your application or if you now want to with everything you read in
Chapter 1.
To use animations, you need to update or add the new imports that will use this new
module:
import {
animate,
query,
state,
style,
transition,
trigger
} from '@angular/animations';
Migrating to Version 4 Chapter ř
The next mostly likely update you'll want to make is to update your templates. As
mentioned in Chapter 1, the Angular team introduced a new ng-template element. The
purpose of this element is to replace the template element for Angular use. Due to this
change, the use of template is deprecated; therefore, you should update all of your instances
from template to ng-template:
<!-- old way -->
<template #loading>Old busted loading...</template>
The last update may not affect you, but if it does, it is a very small change and deals with
the lifecycle events. For events such as OnInit and OnDestroy, you now need to use
implements, not extends:
// if you have
MyComponent extends OnInit
// change to
MyComponent implements OnInit
[ 22 ]
Part 2
This also applies to working with FormControl, FormGroup, or FormArray. You can still
set the updateOn value on the FormGroup and FormControl separately:
this.login = new FormGroup({
name: new FormControl(),
email: new FormControl(null, { updateOn: 'blur' }) // will update on blur
}, { updateOn: 'submit' }); // default will update on submit
Animations
The version 5 release of Angular has additional improvements to animations. One
improvement provides additional error reporting. Animations will throw errors when
invalid CSS properties are detected. This makes it easier to find problems if your animations
aren't working as expected, as it will tell you whether a provided property is not supported.
The Angular team has also worked to reduce the size of the bundle. They've accomplished
this by removing AST classes. Animation has also added the ability for queries to handle
negative numbers. This will match elements from the end instead of from the beginning.
Allowing for negative numbers in queries aligns similarly to how many array functions
work.
[ 25 ]
New Features in Version 5 Chapter Ś
Router events
The next features provides additional router events. The changes add the ability to track the
activation of individual routes as well as provide new events. You can now leverage the
ActivationStart and ActivationEnd, GuardsCheckStart and GuardsCheckEnd, and
ResolveStart and ResolveEnd events:
import {
Router,
ActivationStart,
ActivationEnd
} from '@angular/router';
import 'rxjs/add/operator/filter';
@Component({
selector: 'app-root',
template: `<router-outlet></router-outlet>`
})
export class AppComponent {
constructor(
private router: Router
) {
router.events
.filter(e =>
e instanceof ActivationStart || e instanceof ActivationEnd)
.subscribe(e => console.log( e.toString() ));
}
}
If you want to track specific URLs, you can leverage the RouterEvent and then check the
ID and URL values:
import {
Router,
RouterEvent
} from '@angular/router';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/distinctUntilChanged';
@Component({
selector: 'app-root',
template: `<router-outlet></router-outlet>`
})
export class AppComponent {
constructor(
private router: Router
[ 26 ]
New Features in Version 5 Chapter Ś
) {
router.events
.filter(e => e instanceof RouterEvent)
.filter(e => e.url == '/tracked-route') // filter desired route
.distinctUntilChanged((e1, e2) => e1.id == e2.id && e1.url == e2.url
)
.subscribe(e => {
console.log(e.id + ': ' e.url);
});
}
}
Pipes
The 5.0 release of Angular introduces a large number of changes in pipes. Due to multiple
bugs and browser inconsistencies, the Angular team chose to drop the intl API for data
exported from the Unicode Common Locale Data Repository (CLDR). This causes
breaking changes for any i18n pipes, including date, number, currency, and percent.
The i18n pipes, by default, only contain local data for the language en-US. You can import
new locale data for language and then set the value of LOCALE_ID to another locale. With
this, you no longer need to use the intl poly fill. In addition, the old pipes do still exist, but
the names are changed and found within DeprecatedI18NPipesModule. One important
factor is that it must be imported after CommonModule:
import { NgModule } from '@angular/core';
import { CommonModule, DeprecatedI18NPipesModule } from '@angular/common';
@NgModule({
imports: [
CommonModule,
DeprecatedI18NPipesModule
]
})
export class AppModule { }
The first pipe we'll look into the changes made to is the Date pipe. The predefined formats
now use the patterns given by CLDR. This will mean that there are some changes to the
formats and to the results of the predefined formats. The timezone format z will now fall
back to 0 and display GMT+1 instead of the complete timezone name (such as Eastern
Standard Time).
[ 27 ]
New Features in Version 5 Chapter Ś
There are now some new predefined formats. These include long, full, longTime, and
fullTime:
'long' is shorthand for 'MMMM d, y, h:mm:ss a z', which will create January 31,
2018 at 9:45:02 AM GMT+1
'full' is shorthand for 'EEEE, MMMM d, y, h:mm:ss a zzz', which will create
Wednesday, January 31, 2018 at 9:45:02 AM GMT+01:00
'longTime' is shorthand for 'h:mm:ss a z', which will create 9:45:02 am GMT+1
'fullTime' is shorthand for 'h:mm:ss a zzzz', which will create 9:45:02 am
GMT+01:00
There are also additional form values available to be used, thanks to the inclusion of CDLR.
These are yyy (numeric, 3 digits + zero padded), standalone months (use L up to LLLLL),
week of year (use w or ww), week of month (use W), fractional seconds (use S, SS, or SSS),
extra day periods, and short non-localized timezones.
The Currency pipe has some small changes as well. The default value for symbolDisplay
is now a symbol instead of code. This means you'll see $7.99 instead of USD7.99. This is the
more natural display value for the default. The second parameter is no longer boolean with
the Currency pipe. Instead, you can choose between code, symbol, or symbol-narrow.
You can provide a boolean; however, this is now deprecated and will show a warning
message in the console.
The Percent pipe has some default changes. If you don't specify the number of digits to
round to, the local format will be used. This usually rounds numbers to 0 digits instead of
the previous implementation, which would not round. For example, {{ 2.71828 |
percent }} will output 271% for local en-US. Previously, it would have shown 271.828.
Watch mode
Compilation with ngc now has a watch mode. This makes it easier to use Ahead of Time
(AoT) compilation, hence saving your headaches that you may find in AoT that are missed
in just in time (JIT) compilation. The Angular team also hooked into transforms with
TypeScript 2.3 to speed up the compilation pipeline. They have worked to try and make
AoT compilation fast enough to be used all the time for development purposes. The new
build does incremental AoT and saves 95% of the build time on the Angular team's
machines. This will become the default in the future, so check out this feature in this release.
[ 28 ]
New Features in Version 5 Chapter Ś
To run, you need to run a serve with the AoT flag turned on:
ng serve --aot
Lazy loading
The Angular team has added additional functionality in version 5 to help the migration
from AngularJS. The team has added the ability to lazy load an Angular Module into an
AngularJS application. This helps you upgrade your application in place without needing to
load all the Angular modules immediately when the application bootstraps.
Material Design
One key addition to the Material Design components in Angular 5 is the compatibility with
Angular Universal and server-side rendering. This makes the components more accessible
for production deployments requiring server-side rendering.
[ 29 ]
New Features in Version 5 Chapter Ś
Together, this gives you the pieces to get started with implementing service workers into
your Angular application. The next release of Angular CLI, version 1.6, will include the
features needed to easily implement the service worker into your project to make an
Angular PWA.
You can start playing with service workers now, but you'll have to do some manual set up
to get it up and running. First, you need to install the Angular Service worker:
npm install @angular/service-worker --save
Next, you need to register the service worker in your main app module:
@NgModule({
imports: [
// add following to imports
environment.production ? ServiceWorkerModule.register('/ngsw-
worker.js') : []
],
// other configurations
})
export class AppModule { }
The service worker needs to be a manifest (control) file, which is based on a configuration
file. In the upcoming version 1.6 release of the CLI, the current default created version of the
ngsw-config.json is shown here:
{
"index": "/index.html",
"assetGroups": [{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html"
],
"versionedFiles": [
"/*.bundle.css",
"/*.bundle.js",
"/*.chunk.js"
]
}
}, {
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
[ 30 ]
New Features in Version 5 Chapter Ś
"resources": {
"files": [
"/assets/**"
]
}
}]
}
To create the control file, you can use a CLI included as part of the package. The syntax for
the command is ngsw-config outputFolder sourceConfigFile baseHref. The
outputFolder is the destination to create the file. The sourceConfigFile specifies the
location of the ngsw-config.json file. Finally, you can also specify a base HREF for your
application, which is "/" by default. You'll only need this if you're already setting it as part
of your Angular application compilation as well. An example of the command to run, using
the dist folder and the JSON from the src directory, is shown here:
node_modules/.bin/ngsw-config dist ./src/ngsw-config.json
Lastly, to get everything up and running, you first need to do a production build, run the
preceding command to create the config, and finally, copy the service worker code to your
list folder as well. Finally, you need to run from that dist folder. The full set of commands
you need to run would be as follows:
ng build --prod
node_modules/.bin/ngsw-config dist ./src/ngsw-config.json
cp node_modules/@angular/service-worker/ngsw-worker.js dist/
http-server dist -p 8080
Unfortunately, you can't currently use ng serve to run and test a PWA app. This should
all become easier once we have full Angular CLI integration. From here, the work of
creating a great Progressive Web App starts. You have two locations in the ngsw-
config.json for caching items, assetGroups for resources related to the app version that
may change, and dataGroups for resources independent from the app version, which is
where you can cache API responses. For example, if we want to cache fonts, we can add a
group called fonts and add any resources we want to cache in there related to fonts:
"assetGroups": [
...
{
"name": "fonts",
"resources": {
"urls": [
"https://fonts.googleapis.com/**"
]
}
[ 31 ]
New Features in Version 5 Chapter Ś
}
]
To cache API responses, we set up groups in the dataGroups section. Here, you need to
specify the caching strategy. You can choose freshness for a network-first strategy or
performance for a cache-first strategy. The following example will specify one API for each
strategy:
"dataGroups": [
{
"name": "api-freshness",
"urls": [
"/feed"
],
"cacheConfig": {
"maxSize": 100,
"maxAge": "2d",
"timeout": "1m",
"strategy": "freshness"
}
},
{
"name": "api-performance",
"urls": [
"/profile"
],
"cacheConfig": {
"maxSize": 100,
"maxAge": "2d",
"timeout": "1m",
"strategy": "performance"
}
}
]
This will get you up and running with service workers. As you can see, there is a little bit to
set up, but the next version of the CLI will make this easy out of the box.
[ 32 ]
New Features in Version 5 Chapter Ś
Performance improvement
The Angular team is always looking for performance improvements. You can now use the
native addEventListener for faster rendering. This allows angular to bypass Zone's
addEventListener, because Angular can make assumptions about its event handlers, but
not for zones. In addition, the team has made it possible to bypass zones entirely if you
have an application that is performance focused. You can bypass it with 'noop' as your
ngZone:
As mentioned when discussing watch mode, the team has also sped up the compilation
process significantly by reusing the TypeScript typecheck for template typechecking. With
this, they've added a new option, fullTemplateTypeCheck. This adds extra checks in
templates, including checking expressions inside templatized content, checking the
arguments of calls to the transform function of pipes, and checking references to directives
that were exposed as variables via exportAs.
[ 33 ]
New Features in Typescript 2.4
5
String enums
TypeScript 2.4 has added support for string enums. Enums are useful for mapping out
allowable values. TypeScript has added the ability for enums to contain string values for
initializing:
enum Hand {
Rock: "ROCK",
Paper: "PAPER",
Scissors: "SCISSORS"
It should be noted that string-initialized enums, such as the preceding one, cannot be
reversed-mapped. This means you cannot use Hand["Scissors"] to get the string
Scissors as the original enum member name.
You can see that 20 is a number being resolved for the Promise, not a string as defined, so
this code will throw an error.
TypeScript now provides better checks for type parameter inference from contextual types.
The problem is that values on the right will not always gain types from the left.
let ct: <T>(x: T) => T = y => y;
This code will leave y previously with a type of any. Now, with TypeScript 2.4, the right
implicitly gains type parameters. This will make the code more type safe.
In addition, TypeScript has added stricter checking for generic functions. It will try to unify
type parameters between two single-signature types. This will give stricter checks and may
catch some more bugs:
type A = <T, U>(x: T, y: U) => [T, U];
type B = <S>(x: S, y: S) => [S, S];
function f(a: A, b: B) {
a = b; // Error
b = a; // Ok
}
None of the properties are required, making WeakSettings as weak. TypeScript 2.4 will
now show an error if there is no overlap with the optional properties:
let settings = {
minValue: 5,
unchecked: true
}
[ 35 ]
Migrating to Version 5
6
The goal has always been to make the migration between versions simple. This holds true
for the latest release, with the biggest change coming in pipes. You can choose to keep using
the old pipes with DeprecatedI18NPipesModule; however, the names have changed. The
better choice is to upgrade the pipes, making any changes needed to keep the output of the
pipes to match what you expect (such as with date pipes).
With Angular 4.3, the team introduced the new HttpClient. With version 5, the old HTTP
is deprecated, so you'll want to migrate your code to the new client, as deprecation means it
is marked for deletion in a future major version. You should move from @angular/http to
@angular/common/http. For more information on the new HttpClient, refer to Chapter
1.
Version 4 replaced the <template> tag with <ng-template> and deprecated its use. The
compiler option of enableLegacyTemplate is available, but it's disabled by default. Both
enableLegacyTemplate and <template> are scheduled to be removed in version 6, so if
you are still using them, you should plan to move away at this time.
There is a sizable list of things deprecated since version 4 that have now been removed. This
will list some of the most common or likely ones, but you should check the full release notes
if you are using any deprecated features. You should also move away from anything
deprecated, as they will eventually make their way to this list. NgFor was removed, and
you should use NgForOf instead. This does not impact *ngFor used in templates.
OpaqueToken was removed with version 5, and you should change to using
InjectionToken. The RouterOutlet has dropped some properties from use, including
locationInjector and locationFactoryResolver. The last we'll mention here is that
the TrackbyFn was removed, and you can simply use TrackByFunction instead.
Part 3
Schematics
The Angular CLI's current initiative for custom schematics is also now a part of Angular
Labs. Schematics are your own custom blueprints for generation from the CLI. This means
that you can write your own custom generators. Instead of calls simply like ng generate
service DataService, you will be able to make calls such as ng generate
ngrxService NgrxDataService, which describes your own custom element to create.
Vision for Version 6 ȱȱȱChapter ŝ
ABC
The last of the current initiatives to be added to Angular Labs is ABC: Angular + Bazel +
Closure. This is Google's effort to use Bazel + Closure to create lightning fast build tools.
The goal is to have an AoT build that is as fast as the Just-in-Time development build. This
is based off of Google's use of Bazel and Closure to build from their mono-repo. They are
working to use closure optimizers to save more space as well as Bazel to build as a tool that
can be used for the frontend and backend. This work is early, but can be played with now.
Angular Elements
Angular Elements is a new way to package Angular components. This change will allow
components to be packaged on their own, with the ability to bootstrap themselves and be
run outside of an Angular application. This "hosts" the Angular component inside of its
own custom element. This will help expand the reach of your Angular code by allowing
you to write standalone components that can be embedded in other applications, while still
writing them in Angular. It creates the bridge between the DOM API and the Angular
component. This is still at a very early stage, but promising.
As you can see, there are a lot of exciting large features coming to Angular. The team will
also still keep pushing to improve the core, making it faster and easier.
[ řş ]
Other Books You May Enjoy
If you enjoyed this book, you may be interested in other books by Packt:
Expert Angular 4
Mathieu Nayrolles, Rajesh Gunasundaram, Sridhar Rao
ISBN: 978-1-78588-023-0
Implement asynchronous programming using Angular
Beautify your application with the UI components built to the material design
specification
Secure your web application from unauthorized users
Create complex forms, taking full advantage of 2-way data binding
Test your Angular applications using the Jasmine and Protractor frameworks for
better efficiency
Learn how to integrate Angular with Bootstrap to create compelling web
applications
Use Angular built-in classes to apply animation in your app
Other Books You May Enjoy
[ 4ŗ ]
Other Books You May Enjoy
Essential Angular 4
Victor Savkin, Jeff Cross
ISBN: 978-178829-376-1
Understand why and how to use JIT and AOT compilation in Angular
Bootstrap and inject NgModules
Learn about the component lifecycle
Understand the two phases of Change Detection
Visualize and parse the Injector tree
Understand advanced Lazy Loading
Integrate and run different testing strategies on your code
[ 4Ř ]
Other Books You May Enjoy
[ 4ř ]
Other Books You May Enjoy
[ 4Ś ]
Other Books You May Enjoy
[ 4ś ]
Other Books You May Enjoy
[ 4Ŝ ]