Download as pdf or txt
Download as pdf or txt
You are on page 1of 141

LEARN WITH

ANGULAR 15
COLLECTED ESSAYS ON PROGRAMMING

By Jeffry Houser

https://www.learn-with.com

https://www.jeffryhouser.com

https://www.dot-com-it.com

Version: 2022.15.001
Copyright © 2022 by DotComIt, LLC
About the Author
Jeffry Houser is a technical entrepreneur that likes to share cool stuff with other people.

In the days before business met the Internet, Jeffry obtained a Computer Science degree. He has solved
a problem or two in his programming career. In 1999, Jeffry started DotComIt; a company specializing in
custom application development.

During the Y2K era, Jeffry wrote three books for Osborne McGraw-Hill. He is a member of the Apache
Flex Project and created Flextras; a library of Open Source Flex Components. Jeffry has spoken all over
the US. He has produced hundreds of podcasts, written over 30 professional articles, and blog on a
weekly basis.

In 2014, Jeffry created Life After Flex; an AngularJS training course for Flex Developers. In 2016, Jeffry
launched the Learn With series with books focusing on using Angular with other technologies. Jeffry has
worked with multiple clients building applications across industries including publishing, health care,
real estate, retail, and entertainment streaming.
Contents

LEARN WITH ANGULAR 15 COLLECTED ESSAYS ON PROGRAMMING .................................................................... 2


About the Author .......................................................................................................................................... 3
Preface .......................................................................................................................................................... 7
Introduction .................................................................................................................................................. 8
What is this Book Series About? ............................................................................................................... 8
Who Is This Book for? ............................................................................................................................... 9
Common Conventions............................................................................................................................. 10
Caveats .................................................................................................................................................... 11
Want More? ............................................................................................................................................ 11
Chapter 1: Understanding the Angular Component Lifecycle .................................................................... 12
What is the Component Lifecycle? ......................................................................................................... 12
Set up a Project ....................................................................................................................................... 13
Implement the LifeCycle Methods .......................................................................................................... 14
Test the Component Lifecycle................................................................................................................. 16
Editing a Title in Comp1 ...................................................................................................................... 16
Creating and Destroying Components ................................................................................................ 17
Test the LifeCycle Methods................................................................................................................. 18
Embedded Components ......................................................................................................................... 23
Modify Component 2 .......................................................................................................................... 24
Retest Lifecycle Methods .................................................................................................................... 24
Final Thoughts ......................................................................................................................................... 29
Chapter 2: Understanding Angular Directives ............................................................................................ 30
Types of Directives .................................................................................................................................. 30
Project Setup ........................................................................................................................................... 30
Attribute Directives ................................................................................................................................. 30
Use an Attribute Directive .................................................................................................................. 31
Create an Attribute Directive .............................................................................................................. 33
Using Renderer2 ................................................................................................................................. 36
Exposing other Properties................................................................................................................... 38
Dispatching Events .............................................................................................................................. 40
Applying directive to different elements ............................................................................................ 42
Structural Directives................................................................................................................................ 46
Use ngIf Structural Directive to hide an element ............................................................................... 46
Creating Your own Structural Directive .............................................................................................. 49
Final Thoughts ......................................................................................................................................... 62
Chapter 3: Debug Applications from Your Browser .................................................................................... 63
Use Outputs and Alerts ........................................................................................................................... 63
Review the Network Tab......................................................................................................................... 66
Use a Step Debugger ............................................................................................................................... 71
Debugging Angular with Augury ............................................................................................................. 77
Install Augury ...................................................................................................................................... 77
Look at NgModules ............................................................................................................................. 77
Review the Component Tree .............................................................................................................. 78
Look at the Router .............................................................................................................................. 82
Final Thoughts ......................................................................................................................................... 84
Chapter4: Using Redux with Angular .......................................................................................................... 85
Understanding Redux Terminology ........................................................................................................ 85
Understanding Redux Flow ..................................................................................................................... 85
Create a Vanilla JavaScript Sample ......................................................................................................... 86
Set up the Infrastructure..................................................................................................................... 86
Saying Goodbye .................................................................................................................................. 89
Define an Initial State.......................................................................................................................... 91
Split up the Reducer ............................................................................................................................ 92
Using the combineReducers( ) function.............................................................................................. 93
Using ngrx ............................................................................................................................................... 94
Setup the Application.......................................................................................................................... 94
Create Your Actions ............................................................................................................................ 95
Create your Reducer ........................................................................................................................... 95
Modify the AppComponent ................................................................................................................ 97
Create the View................................................................................................................................... 99
Run the App ........................................................................................................................................ 99
Combing Reducers with ngrx ................................................................................................................ 102
Create the Reducers.......................................................................................................................... 102
Modify the AppModule..................................................................................................................... 102
Modify the View ................................................................................................................................ 103
Retest the App .................................................................................................................................. 104
Final Thoughts ....................................................................................................................................... 105
Chapter 5: Standalone Components ......................................................................................................... 106
Create Your first Standalone Component ............................................................................................. 106
Using the Component ........................................................................................................................... 108
Using Multiple Components ................................................................................................................. 110
Using Providers ..................................................................................................................................... 115
How to use Embedded Standalone Components ................................................................................. 119
Component Level Services .................................................................................................................... 123
Routes and Lazy Loading ....................................................................................................................... 124
Bootstrap an Application without using a Module ............................................................................... 130
Testing a Standalone Component ......................................................................................................... 134
Final Thoughts ....................................................................................................................................... 140
Afterword .................................................................................................................................................. 141
Preface
I was a Flex developer for a long time, and a ColdFusion developer for an even longer time. Those
technologies don’t matter a lot in today’s market. A smart developer will spend time educating himself
on new technologies to keep up with a changing market, and to make sure he has healthy job prospects
in the future. I’ve reinvented myself more times than I can count. While cultivating new skills for the
HTML5 world, I decided to write about my experiences. With this series of books, you can leverage my
experience to learn quickly.

This book is about my experiences building Angular applications. Angular is an HTML5 framework built
by Google for building smart user interfaces. It is built on TypeScript and allows you to build dynamic
views in HTML5. It is fully testable, which is important to many enterprise-level applications. It has a
large developer community, ready to help with problems. I greatly enjoy building applications with
Angular.

This book contains a series of essays around important parts of Angular and the HTML5 ecosystem that
were not covered as part of the main series.
Introduction
What is this Book Series About?
The purpose of this series is to teach by example. The plan is to build an application using multiple
technologies. These books will document the process, with each book focusing on a specific technology
or framework. This entry is a companion to the Angular books and covers important Angular coding
concepts in depth that weren’t used in the main books.

This book covers:

• Components: A deep dive into understanding the Angular Component Lifecycle.


• Application debugging: Code isn’t perfect the first time you write it; and this chapter will show
you techniques to debug your HTML5 application.
• Redux: Redux is a state framework that is commonly used with React, however it can be used
with Angular too. We’ll teach you all about it.
• Directives: Directives are like creating your own attribute that can apply to any HTML Tag, even
other Angular components.

These are important topics to add to your development toolbox.


Who Is This Book for?
Want to learn about building HTML5 applications? Are you interested in Angular or Bootstrap? Do you
want to learn new technologies by following detailed examples with runnable code? If you answered yes
to any of these questions, then this book is for you!

Here are some topics we’ll touch upon in this book, and what you should know before continuing:

• TypeScript: This is the language behind Angular. It is a statically typed language that compiles to
JavaScript. The more you know about it, the better. If you are not familiar with it yet, check out
our tutorial lesson on learning the basics of TypeScript.
• Angular: If you read the main books of this series, then you should have more than enough
Angular experience to understand its usage here.
• NodeJS: We use these scripts to compile our TypeScript into JavaScript, process CSS, and copy
files. Familiarity with NodeJS will be beneficial
Common Conventions
I use some common conventions in the code behind this book.

• Classes: Class names are in proper case; the first character of the class in uppercase, and the
start of each new compound word being in uppercase. An example of a class name is MyClass.
When referencing class names in the book text, the file extension is usually referenced. For
TypeScript files that contain classes the extension will be “ts”. For JavaScript files, the extension
is “js”.
• Variables: Variable names are also in proper case, except the first letter of the first compound
word; it is always lowercase. This includes class properties, private variables, and method
arguments. A sample property name is myProperty.
• Constants: Constants are in all uppercase, with each word separated by an underscore. A
sample constant may be MY_CONSTANT.
• Method or Function Names: Method names use the same convention as property names. When
methods are referenced in text, open and close parentheses are typed after the name. A sample
method name may be myMethodName().
• Package or Folder Names: The package names—or folders—are named using proper case again.
In this text, package names are always referenced as if they were a directory relative to the
application root. A sample package name may be com/dotComIt/learnwith/myPackage.
Caveats
The goal of this book is to help you become productive creating HTML5 apps with a focus on Angular. It
leverages my experience building business apps but is not intended to cover everything you need to
know about building HTML5 Applications. This book purposely focuses on the tool chain and
complimentary libraries. If you want to know more about Angular explicitly, check out original series.
You should approach this book as part of your learning process and not as the last thing you’ll ever need
to know. Be sure that you keep educating yourself. I know I will.

I am writing these books as a labor of love and do not have the resources of a major publisher. Although
we try our hardest sometimes mistakes slip through. It might be a minor typo, or formatting issue. It
could be an error in code. I hate it when this stuff happens. If you find something that is off, be sure to
let us know and we’ll reward you with a free upgrade to the latest—or next—edition of this book, or
access to some of our books covering other technologies.

Want More?
You should check out this book’s web site at www.learn-with.com for more information, such as:

• Source Code: You can find links to all the source code for this book and others.
• Errata: If we make mistakes, we plan on fixing them. You can always get the most up-to-date
content available from the website. If you find mistakes, please let us know.
• Test the Apps: The web site will have runnable versions of the app for you to test.
• Bonus Content: You can find more articles and books expanding on the content of this book.
Chapter 1: Understanding the Angular Component Lifecycle
Angular components are one of the primary building blocks of an Angular application, and it helps to
understand how Angular creates a component and how your own components can leverage some
lifecycle hooks in order to make your components work as efficiently as possible.

What is the Component Lifecycle?


The Angular Component Lifecycle is a bunch of methods that Angular will try to execute on a component
throughout the component’s life. A component’s life starts with the component creation. Many
methods will run over and over as part of the component’s render cycle. This is how things like binding
work. Finally, a component is destroyed or taken off the view stack and garbage collected. Each
method is a hook that allows us to run our own code during that life cycle event.

Let’s start by reviewing the component creation cycle:

• ngOnChanges(): This event is fired when Angular sets or changes input properties. It receives
an object of current and previous property values. I’ve used this for date formatting from UTC
to the user’s specific time zone.
• ngOnInit(): This method is run directly after ngOnChanges(). I use it to set up things or trigger
remote service calls, almost like a constructor for Angular. It is not uncommon to use this to
trigger a data loading service.
• ngDoCheck(): This method is called next, and is used to act on changes that Angular won’t
detect on its own. I’ve used this to update data flags, such as whether an object has been
changed or not.
• ngAfterContentInit(): This relates to the use of ng-content, or transclusion. After the wrapped
contents are placed inside the component’s template, this method fires. It is run after the first
ngDoCheck(). I’ve never actually used this one.
• ngAfterContentChecked(): After ngAfterContentInit(), this method is executed. I haven’t used
this one either.
• ngAfterViewInit(): After Angular finishes initializing the view template, including all the children.
I might use this to clear a loading symbol or something similar.
• ngAfterViewChecked(): This fires after Angular completes the check of the component’s views
and children. I might use this to clear a loading symbol or something similar.

Once a component is created, Angular is continuously evaluating it to look for changes due to user
interaction or responses from remote service calls. The process is similar, but simpler:

• ngOnChanges(): This event is fired when Angular sets or resets input properties. It receives an
object of current and previous property values.
• ngDoCheck(): This method is called immediately next, and is used to act on changes that
Angular won’t detect on its own.
• ngAfterContentChecked(): After ngDoCheck(), this method is executed.
• ngAfterViewChecked(): This fires after Angular completes the check of the component’s views
and children.
The biggest change here is that ngOnInit(), ngAfterContentInit(), and ngAftertViewInit() are not part of
the normal render lifecycle. Whether you use an init method or a check method depends on whether
you want to do something every time Angular checks the component, or just once. The ngOnChanges()
and ngDoCheck() are executed a lot and I try to avoid using them as much as possible. They can cause
performance issues and putting code in these methods is often hard to debug.

The destruction lifecycle only has a single method:

• ngOnDestroy(): This is called right before Angular removes a component from view. The most
common use case for this method is to unsubscribe from observables and to detach event
listeners to help improve app memory usage.

All these methods can be implemented within your component to help time changes for efficiency.

Set up a Project
Let’s create a sample project. First you’ll want to set a project with the Angular CLI:
ng new

You can step through the wizard:

I did not use strict typing but did add Angular routing and decided to use normal CSS.

Generate a few components:


ng generate component view/comp1

and:
ng generate component view/comp2

You should see something like this:


I think that is all the setup you need. You can test out your project by running:
ng serve

And loading localhost:4200 in your browser.

Implement the LifeCycle Methods


Let’s implement the lifecycle methods in each of our components. Open up comp1.component.ts.
You’ll see the ngOnInit() is already in there:
export class Comp1Component implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

Two things I want to highlight. There is an interface OnInit that the component implements. That
interface contains a single method, ngOnInit(). All the lifecycle methods have a similar interface.

We can implement all the interfaces:


export class Comp1Component implements OnInit, OnChanges, DoCheck,
AfterContentInit, AfterContentChecked,
AfterViewInit, AfterViewChecked,
onDestroy {

And add all the methods:


ngOnInit(): void {
console.log('comp1 ngOnInit');
}

ngOnChanges(changes: SimpleChanges): void {


console.log(' comp1 ngOnChanges');
console.log(changes)
}
ngDoCheck(): void {
console.log('comp1 ngDoCheck');
}
ngAfterContentInit(): void {
console.log('comp1 ngAfterContentInit');
}
ngAfterContentChecked(): void {
console.log('comp1 ngAfterContentChecked');
}
ngAfterViewInit(): void {
console.log('comp1 ngAfterViewInit');
}
ngAfterViewChecked(): void {
console.log('comp1 ngAfterViewChecked');
}
ngonDestroy(): void {
console.log('comp1 ngOnDestroy');
}

I added a console.log() statement for each method in order to keep track of the order of operations in
the browser’s log. I also added a log to the constructor:
constructor() {
console.log('comp1 constructor');
}

You’ll need to modify the imports to bring in all the interfaces:


import {
AfterContentChecked, AfterContentInit, AfterViewChecked,
AfterViewInit, Component, DoCheck, OnChanges, OnDestroy, onInit,
SimpleChanges
} from '@angular/core';

Let’s do something very similar in the comp2.component.ts:


export class Comp2Component implements OnInit, OnChanges, DoCheck,
AfterContentInit, AfterContentChecked,
AfterViewInit, AfterViewChecked,
OnDestroy {
constructor() {
console.log('comp2 constructor');
}
ngOnInit(): void {
console.log('comp2 ngOnInit');
}
ngOnChanges(changes: SimpleChanges): void {
console.log('comp2 ngOnChanges');
console.log(changes)
}
ngDoCheck(): void {
console.log('comp2 ngDoCheck');
}
ngAfterContentInit(): void {
console.log('comp2 ngAfterContentInit');
}
ngAfterContentChecked(): void {
console.log('comp2 ngAfterContentChecked');
}
ngAfterViewInit(): void {
console.log('comp2 ngAfterViewInit');
}
ngAfterViewChecked(): void {
console.log('comp2 ngAfterViewChecked');
}
ngonDestroy(): void {
console.log('comp2 ngOnDestroy');
}
}

Now we have two components with all the life cycle methods implemented, so let’s get to building some
tests.

Test the Component Lifecycle


Let’s get to building some proof of concept samples to see how these lifecycle methods work. We’ll
flesh out the Comp1Component to accept an input, use ng-content, and dispatch an event. Then we
can create and remove a bunch of instances of comp1 to watch the lifecycle method order.

Editing a Title in Comp1


Let’s focus on comp1 first. We’re going to pass a single value into it:
@Input()
title: string;

And we can have an output:


@Output()
titleChanged: EventEmitter<string> = new EventEmitter<string>();

Let’s add one more event:


@Output()
deleteRequest: EventEmitter<any> = new EventEmitter<any>();

Be sure to modify imports:


import {
AfterContentChecked, AfterContentInit, AfterViewChecked,
AfterViewInit, Component, DoCheck, EventEmitter, Input,
OnChanges, OnInit, Output,SimpleChanges
} from '@angular/core';

Switch over to the app.module.ts and load the FormsModule into the angular module metadata:
imports: [
BrowserModule,
AppRoutingModule,
FormsModule
],

Don’t forget the class import:


import {FormsModule} from "@angular/forms";

Now switch over to comp1.component.html. Replace all the contents with this:
<hr>
<input type="text" [(ngModel)]="title" (change)="onChange($event)"><br/>
<button (click)="onDeleteRequest()">Delete</button>
<hr>
<ng-content></ng-content>

There is an input that allows you to tweak the title. It will also call the onChange() event when
something changes. A Delete button makes a call to onDeleteRequest(). And finally, the wrapped
content is at the bottom with the ngContent tag.

Implement the onChange() method inside of comp1.component.ts:


onChange(event) {
this.titleChange.emit(this.title);
}

This just sets the dispatches the titleChange event with the new title value. The title is automatically
updated when the model changes.

This is the onDeleteRequest() method:


onDeleteRequest(): void{
this.deleteRequest.emit();
}

It emits the deleteRequest() method and does nothing else. Now let’s move onto creating the app.

Creating and Destroying Components


We’ve built the component but aren’t using it yet. We can’t see the logs for the lifecycle events without
creating instances of the component. Let’s loop over to the app.component.ts file.

First, replace the title with a title string with a titles array:
titles = [{title: 'componentlifecycle'}];

The titles array contains an array of objects, with each object having a single title property. To create, or
add, components on the fly we’ll just add, or remove, items from this array.

Open the app.component.html. First, let’s add an add button to add additional objects onto our array:
<button (click)="add()">Add</button><br/><br/>
This is the add() method inside of the app.component.ts:
add() {
this.titles.push({title: 'componentlifecycle'});
}

It just hard codes a new entry on the titles array, which Angular will automatically know to re-draw the
HTML Template to add more items.

Back to the app.component.html, we’re going to loop over the titles array to create instances of the
Comp1Component and inside that component we’ll add another input that edits the same data. The
two-way binding between the two components will fire off the life cycle methods:
<div *ngFor="let title of titles; let i = index">
<app-comp1 [(title)]="title.title" (deleteRequest)="onDeleteRequest(i)">
{{i}}. <input type="text" [(ngModel)]="title.title" >
</app-comp1>
</div>

Each input refers to the title property on one of our objects, as does each instance of the
Comp1Component.

The Comp1Component also includes a listener for the deleteRequest() event. The deleteRequest()
method has a single argument, the index of the item that is going to be deleted. Let’s open up
app.component.ts to see the onDeleteRequest() method:
onDeleteRequest(index) {
this.titles.splice(index, 1);
}

This uses the JavaScript splice() to remove the selected item from the array.

Test the LifeCycle Methods


Run the app:
The first input is the internal input, followed by the delete button. The second input is the parent input,
which was injected and placed using the ngContent tag. Play around with this. Add items, delete items,
change text both inside the component and outside the component. Let’s see what happens for each
one.

First take a look at the console upon first creation:


These things happen:

1. First the constructor runs


2. Then the ngOnChanges() runs for the first time. The change object in it highlights that the title
has changed. Important to remember that all the properties are set before the ngOnInit()
executes.
3. Next, the ngOnInit(), this is treated like an Angular constructor.
4. Then ngDoCheck() executes for the first time.
5. Then ngAfterContentInit() is fired. This is the initialization of the wrapped content—the
parent’s text input.
6. The ngAfterContentChecked() fires, finishing off the content initialization check.
7. The ngAfterViewInit() is run, meaning the view template has been initialized and is ready for
interaction.
8. Finally the ngAfterViewChecked() is executed.

That sums up the component creation lifecycle. Notice as part of the loading process we immediately
jump into one redraw process:

1. Then ngDoCheck() executes for the second time.


2. The ngAfterContentChecked() fires.
3. Finally the ngAfterViewChecked() is executed.

The ngOnChanges() method did not execute for this redraw cycle because the title had not changed.

Now change the value in the first input:


The life method went through, but notice that I still have focus on the text in the child component, so
the titleChange event has not fired yet, and the parent’s input hasn’t changed yet. Click off the field and
you’ll see a flurry of activity:
The first three events are leftover from the previous screenshot, so we want to start reviewing after
that. Once the input loses focus and the titleChange event is emitted we have an ngOnChanges() event.
Then the redraw cycle happens three times. A lot of things, such as button clicks or losing focus on a
component can trigger the redraw cycle. It is important to understand this goes on a lot.

Now click the delete button:

I cleared the console before clicking the delete, button, but you can see in the app our input is gone and
that the ngOnDestroy() lifecycle hook was executed. Feel free to click the add button again and play
around some more.

Embedded Components
Earlier in this chapter I created two separate components. We’ve fleshed out Comp1Component a lot
but have not done anything with Comp2Component. We’re going to add a title property to
Comp2Component and display it to demonstrate how the lifecycle events work between components in
a parent and child relationship.
Modify Component 2
For Comp2Component we’re going to pass in a title and display it. It won’t fire as many component
methods in Comp2 as it will for Comp2, but it should give us a sample of how they all work together.
First, create a title input in comp2.component.ts:
@Input()
title: string;

You’ll want to be sure to import the Input:


import {
AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit,
Component, DoCheck, Input, OnChanges, OnInit, SimpleChanges
} from '@angular/core';

Now open up the comp2.component.html. Replace the contents with this:


{{title}}

It just displays the title, nothing more.

Now move over to comp1.component.html. Between the input and the delete button, drop an instance
of Comp2Component:
<input type="text" [(ngModel)]="title" (change)="onChange($event)"><br/>
<app-comp2 [title]="title"></app-comp2><br/>
<button (click)="onDeleteRequest()">Delete</button>

That should be enough to get us moving.

Retest Lifecycle Methods


Reload the app in the browser and take a look at the console:
Time to examine the order of operations:

1. First the constructor runs for Comp1Component.


2. Then the constructor runs for Comp2Component.
3. Then the Comp1Component’s ngOnChanges() method runs for the first time. The change
object in it highlights that the title has changed, being passed in from the parent.
4. Next, the ngOnInit() runs for Comp1Component, this is treated like an Angular constructor.
5. Then Comp1Component’s ngDoCheck() executes for the first time.
6. Then ngAfterContentInit() for Comp1Component is fired. This is the initialization of the
wrapped content—the parent’s text input.
7. The Comp1Component ngAfterContentChecked() fires, finishing off the content initialization
check.
8. Now Comp2Component starts its life cycle running, ngOnChanges(). The title is being passed in
from Comp1Component.
9. Comp2Component’s ngOnInit() is run.
10. The ngDoCheck() is run for Comp2Component.
11. The afterContentInit() runs in Comp2Component.
12. Then, ngAfterContentChecked() fires in Comp2Component.
13. Comp2Component’s ngAfterViewInit() takes the next spot.
14. The last setup for Comp2Component runs, ngAfterViewChecked()
15. Moving back to Comp1Component, the ngAfterViewInit() is run, meaning the view template
has been initialized and is ready for interaction.
16. Finally the ngAfterViewChecked() is executed.

That sums up the component creation lifecycle. Comp2Component goes through its life cycle as part of
Comp1Component’s view initialization.

At the end of the image, we see an immediate jump into the redraw process for both comp1 and comp2
here:

1. First, Comp1Component’s ngDoCheck() executes for the second time.


2. ngAfterContentChecked() fires in Comp1Component.
3. Then Comp2Componet’s dispatches its own ngDoCheck().
4. Followed by Comp2Component’s ngAfterContentChecked()
5. Comp2Component finishes up with ngAfterViewChecked().
6. And finally Comp1Component’s ngAfterViewChecked() is finishes the screen display.

The ngOnChanges() method does not execute for this redraw cycle because the title had not changed
for either component.

Now change the value in the first input:


The non-creation based method went through. Notice that the ngOnChanges() was fired for
Comp2Component but not for Comp1Component. This is because the value inside Comp1Component
changed, but the value in the parent did not change. Comp2Component binds to the
Comp1Component value, which is what that fired. But Comp1Component’s values didn’t change
externally so no need for it to run ngOnChanges().

Click off the field and you’ll see a flurry of activity as the titleChange event dispatches out of
Comp1Component:
Once we lose focus and the titleChange event is emitted we have an ngOnChanges() event in
Comp1Component. The event triggers a change to the parent’s value, so this makes sense. Then the
redraw cycle happens three times. I said previously, the redraw cycle will happen a lot in the life of a
component.

Now click the delete button:

I cleared the console before clicking the delete, button, but you can see in the app our input is gone and
that the ngOnDestroy() lifecycle hook was executed, first for Comp2Component and then for
Comp1Component. The deletions happen from the bottom up. You should click the add button again
and play around some more.

Final Thoughts
At this point you should understand the Angular Component LifeCycle methods, and when they execute,
and some inkling of what you might use them for. Understanding these methods and leveraging them is
important to writing performant Angular applications.
Chapter 2: Understanding Angular Directives
An Angular Directive is a way to create your own HTML Attribute. They can be applied to any tag,
including an existing HTML tag or your own Angular custom components. From an implementation
standpoint, directives are just like Angular components except they have no template. This article will
teach you how to use some directives that are part of the Angular library and will show you how to
create your own.

Types of Directives
There are two types of directives:

• Attribute Directives: Attribute directives are used to modify an element it placed on. Some
examples might be ngClass which is used to add more styles to the directive or click, which is
used to respond to custom user interaction.
• Structural Directives: Structural directives change the DOM of the HTML page by adding or
removing items. Examples of this might be *ngIf which removes or adds an element from the
page, or *ngFor which will create new elements.
We’ll go into full details of each type of directive and show you how to use existing directives, as well as
creating your own.

Project Setup
Before going into the samples, you’ll need to create an Angular project. I used the Angular CLI to do so:
ng new

You’ll see something like this:

I named the project ud, for Understanding Directives. I set up routing and used regular CSS.

In the app.component.html file, delete everything except the router-outlet, so the file looks like this:

<router-outlet></router-outlet>
You can run the app, but you won’t see much until we start adding routes.

Attribute Directives
Let’s start looking at attribute directives. I’m going to use an existing one that is built as part of the
Angular framework first, and then show you how to create your own.
Use an Attribute Directive
For this sample, we’re going to use ngClass in order to change styles to swap the look and feel of a
button, switching from black text on a white background to white text on a black background. First let’s
create a component:

ng generate component use-attribute-directive


You’ll see something like this:

Open up the app-routing.module.ts file and a sample1 route to the Routes array:
const routes: Routes = [
{path: 'sample1', component: UseAttributeDirectiveComponent},
{ path: '**', redirectTo: '/sample1'}
];

I also added a generic redirect that will always show us sample1.

Let’s create our styles in use-attribute-directive.component.css:


.regular {
background: #ffffff;
color: #000000;
}

.reversed {
background: #000000;
color: #ffffff;
}

I created a regular style and a reversed style, setting both the background color and the text color.

Switch over to the use-attribute-directive.component.html template:


<button (click)="reverseState()"
[ngClass]="{ 'regular':!reversedState, 'reversed':reversedState}">
Reverse State
</button>

A button exists, and the click handler to call a reverseState() method. The ngClass accepts an object as
an argument. The object contains the name of the CSS classes that will be applied to the button if the
value of the class is true. The regular CSS state is applied if the reversedState value is false, and
reversed CSS is applied of the reversedState value is true.
We’ll have to create the reverseState() method and the reversedState value inside the use-attribute-
directive.compoment.html, so let’s do that now. First the reversedState vallue:
reversedState = false;

I set the default condition to false, meaning the button will start in the regular state.

Now, create the reverseState() method:


reverseState() {
this.reversedState = !this.reversedState;
}

This just toggles the reversedState value.

Try to run the app. You should see the default state:

Click the button and you’ll see the state swap:


It is pretty common to use directives like this within an Angular application.

Create an Attribute Directive


Now, we’re going to take the previous sample one step further. Instead of using the existing ngClass
directive to toggle the state of a button, let’s create our own directive to switch any HTML element
between two separate states.

First, we’ll do some setup. Create a component for creating our own attribute directive:
ng generate component create-attribute-directive

You’ll see something like this:

Open up the app-routing.module.ts file and a sample2 route to the Routes array:
const routes: Routes = [
{path: 'sample1', component: UseAttributeDirectiveComponent},
{path: 'sample2', component: CreateAttributeDirectiveComponent},
{ path: '**', redirectTo: '/sample1'}
];

Now, use the Angular CLI to create our first directive:


ng generate directive directives/reverse

You’ll see something like this:

I put the new directive in the directive directory. If nothing is specified it will be put in src/app by
default, but long term I like to keep my code better organized without a lot of things in the main app
directory. Open up the reverse.directive.ts:
import { Directive } from '@angular/core';
@Directive({
selector: '[appReverse]'
})
export class ReverseDirective {
constructor() { }
}

First, we import the Directive class. This is metadata used to define the directive. The only thing we
define, at this point in the metadata is the selector. We’ll use this when we apply the directive to an
HTML element, the Angular module, something like this:
<button appReverse></button>

Right now, the directive doesn’t do anything, but we’ll come back to this in the HTML template later. It
is strongly recommended you do not name your custom directives with a prefix ng because that is used
by the Angular framework and we want to avoid conflicts with other existing directives.

I want to note that the directive is loaded in the main Angular module. Open up app.module.ts and
you’ll see it in the declarations section:
@NgModule({
declarations: [
AppComponent,
UseAttributeDirectiveComponent,
CreateAttributeDirectiveComponent,
ReverseDirective
],
// other stuff
})

If you do not add your directive to the @NgModule your app won’t know how to find it and you’ll get
compiler errors.

The first thing we want to do is inject the ElementRef into the directive class:
constructor(private el: ElementRef) { }

Dependency Injection for Directives works just like it does for other components, so we inject the value
into the constructor. This will give the directive class a reference to the component which is was placed
on.

This directive needs to pass in a value of the directive name, and then make changes to the
ElementRef’s styles based on that. To do that we’ll need to define an Input() metadata. The simplest
way to do this:
@Input('appReverse') reversedState: Boolean;

When the directive sees the appReverse directive applied to an HTML tag as an attribute, the value will
be set in the reversedState value inside the directive class. In order to run some code whenever that
value changes I’m going to switch it to a get/set method:
private _reversedState = false;
@Input('appReverse')
get reversedState() {
return this._reversedState;
}
set reversedState(input) {
this._reversedState = input;
this.changeState();
}

The get and set methods are pretty standard. A private variable holds the state. The get method will
return that private variable, and the set method will set it. The set method also runs a changeState()
method, so let’s look at that:
changeState() {
if (this.reversedState) {
this.el.nativeElement.style.backgroundColor = '#000000';
this.el.nativeElement.style.color = '#ffffff';
} else {
this.el.nativeElement.style.backgroundColor = '#ffffff';
this.el.nativeElement.style.color = '#000000';
}
}

This method checks the reversedState value and sets the background and foreground styles. I use
nativeElement property on the ElementRef to drill down into the component and set specific styles. For
the moment, I’m hard coding the color values, but we’ll revisit that in a later sample.

How do we use the directive? Open the create-attribute-directive.component.html file:


<button (click)="reverseState()" [appReverse]="reversedState">
Reverse State
</button>

The appReverse directive is placed directly on the button; and it is given the value of reversedState,
which is a Boolean value in the component that we’ll create. The click button is used to call a
reverseState() method that will toggle the reversedState property.

Open the create-attribute-directive.ts file. First create the reversedState property:


reversedState = false;

Then add the reverseState() method:


reverseState() {
this.reversedState = !this.reversedState;
}

We’ve seen this method, and property, set up identically in the previous sample. The major change is in
how the new styles are applied to the button.

Rerun the app:


Click the button and the state should switch:

Play with it to switch the state back and forth.

Using Renderer2
If you read the docs on the ElementRef’s nativeElement property, there is a big warning to avoid using
it. It breaks encapsulation by accessing the DOM directly, and can lead to unexpected results in the
application. We’re going to use the Renderer2 component instead. It is designed to give a layer of
abstraction between Angular and the DOM within directives like this. While we’re at it, I’m also going to
switch to using a CSS Class instead of accessing styles directly.

The first step is to inject the Renderer2 into the directive’s reverse.directive.ts file:
constructor(private renderer: Renderer2, private el: ElementRef) { }

The reversedState property remains unchanged, but we will want to modify the changeState() method:
changeState() {
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, 'regular');
this.renderer.addClass(this.el.nativeElement, 'reversed');
} else {
this.renderer.removeClass(this.el.nativeElement, 'reversed');
this.renderer.addClass(this.el.nativeElement, 'regular');
}
}

Instead of drilling down into the nativeElement directly, we’re calling the addClass() and removeClass()
methods on the renderer, and passing in the nativeElement along with the new style. We could have
done the same thing with the previous sample, using addStyle() and removeStyle() methods on the
renderer.

Let’s be sure to add our regular and reversed styles to create-attribute-directive.css:


.regular {
background: #ffffff;
color: #000000;
}

.reversed {
background: #000000;
color: #ffffff;
}

Rerun the code:

Then click the button:


No change from the previous implementation, we just have a different, better, implementation under
the hood.

Exposing other Properties


It is a problem that we are hard coding the style values inside the directive. That is horrible use of
encapsulation and limits reuse, so let’s open those up. Open up reverse.directive.ts:
@Input() regularCSSClass: string;
@Input() reversedCSSClass: string;

I added one input for the regularCSSClass and one for the reversedCSSClass. Now move to the
changeState() function:
changeState() {
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, this.regularCSSClass);
this.renderer.addClass(this.el.nativeElement, this.reversedCSSClass);
} else {
this.renderer.removeClass(this.el.nativeElement, this.reversedCSSClass);
this.renderer.addClass(this.el.nativeElement, this.regularCSSClass);
}
}

Instead of accessing hard coded values as the CSS Class is added, or removed, from the native element
the variables are added.

Notice how the values have no default styles. To solve that we’ll make sure to call the changeState()
method when ngOnInit() runs, which will be after the property values are set. First implement the
OnInit interface as part of the class definition:
export class ReverseDirective implements OnInit {

Then add the ngOnInit() method:


ngOnInit() {
this.changeState();
}

This will make sure that the default states are set after the component is initialized.

Open up create-attribute-directive.component.html and add in our two new properties:


<button (click)="reverseState()"
[appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">
Reverse State
</button>

Angular’s magic under the hood will know the new attributes belong to the directive and will pass in
those values.

Rerun the app:

Then click the button:


And you’re probably getting bored of seeing these screenshots repeated, but don’t worry I won’t show
them again.

The new Angular directive inputs were set up as regular HTML attributes with string values, but we
could set them up as Angular attributes with an Angular expression as the value. In the simplest form,
like this:
<button (click)="reverseState()"
[appReverse]="reversedState"
[regularCSSClass]="'regular'"
[reversedCSSClass]="'reversed'">
Reverse State
</button>

The Angular expression is a literal string, and the regularCSSClass and reversedCSSClass are enclosed in
brackets.

Dispatching Events
A directive can dispatch its own events, just like a component can. Let’s add an event to the directive
that will dispatch whenever the state changes. First, I’ll add a new class:
export class CSSReversedEvent {
addedCSSClass: string;
removedCSSClass: string;
}

I put this class in the reverse.directive.ts file, instead of creating its own class file. It includes one value
for the CSS Class that was removed, and one for the CSS Class that was added.

Now inside the ReverseDirective class, add the output event:

@Output() stateChange: EventEmitter<CSSReversedEvent> = new EventEmitter();


This uses the @Output() metadata to create the EventEmitter named stateChange. How look at the
changeState() method:
changeState() {
const newState: CSSReversedEvent = new CSSReversedEvent();
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, this.regularCSSClass);
this.renderer.addClass(this.el.nativeElement, this.reversedCSSClass);
newState.addedCSSClass = this.reversedCSSClass;
newState.removedCSSClass = this.regularCSSClass;
} else {
this.renderer.removeClass(this.el.nativeElement, this.reversedCSSClass);
this.renderer.addClass(this.el.nativeElement, this.regularCSSClass);
newState.addedCSSClass = this.regularCSSClass;
newState.removedCSSClass = this.reversedCSSClass;
}
this.stateChange.emit(newState);

The first line in the method creates a new instance of the CSSReversedEvent class. The middle of the
method will add the CSS Values onto this new object, depending on which state we are entering. The
final name of the method will dispatch the event.

Open up the create-attribute-directive.html file and add in the stateChange event listener:
<button (click)="reverseState()"
[appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed"
(stateChange)="onStateChange($event)">
Reverse State
</button>

The event listener will call the onStateChange() event inside the create-attribute-
directive.component.ts file:
onStateChange(event) {
console.log(event);
}

For simplicity I just outputted the event to the console.

Rerun the code and start clicking buttons:


During component initialization this event is dispatched twice. Once after the reversedState value is
set, but before the regularCSSClass and reversedCSSClass are set. We see the event dispatching
undefined for each class in this case. Then it is dispatched a second time after the initialization is
complete. This is when the initial styles are applied to the button.

Click the button a few times to see the events continue to dispatch:

You should realize now that there is a lot you can do with directives.

Applying directive to different elements


All our samples so far have been applying the styles to the button, but we can easily use this same
directive on other elements; here it is in a p tag and a div:
<p [appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">
The directive in a p!
</p>
<div [appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">
The directive in a div!
</div>

The button is still in the view, and can be used to toggle:


Click the button and everything is reversed:
This is where we start to see the real power of encapsulating this in a directive. We are now writing
simpler code than we would have if we were trying to do this using ngClass. Let’s add four new styles
into the create-attribute-directive.component.css:
.regular-red {
background: #ffffff;
color: #ff0000;
}

.reversed-red {
background: #ff0000;
color: #ffffff;
}

.regular-blue {
background: #ffffff;
color: #0000ff;
}

.reversed-blue {
background: #0000ff;
color: #ffffff;
}

The styles use red and white, or blue and white instead of our usual black and white. Apply them to
HTML elements in create-attribute-directive-component.html:
<p [appReverse]="reversedState" regularCSSClass="regular-red"
reversedCSSClass="reversed-red">
The directive in a p!
</p>

<div [appReverse]="reversedState" regularCSSClass="regular-blue"


reversedCSSClass="reversed-blue">
The directive in a div!
</div>

The red style is applied to the p tag and the blue styles are applied to the div. Rerun the code:
And click to switch:
Structural Directives
An attribute directive is one that will add or remove items from the HTML. I’m going to show you how to
use one of the built in Angular directives and then we’ll go into details on how you can create your own.

Use ngIf Structural Directive to hide an element


I’m going to demonstrate using ngIf as a structural directive. To add or remove an element from the
page. Start by creating a component for using a structural directive:
ng generate component use-structural-directive

You’ll see something like this:

Open up the app-routing.module.ts file and add a sample3 route to the Routes array:
const routes: Routes = [
{path: 'sample1', component: UseAttributeDirectiveComponent},
{path: 'sample2', component: CreateAttributeDirectiveComponent},
{path: 'sample3', component: UseStructuralDirectiveComponent},
{ path: '**', redirectTo: '/sample1'}
];

Now open use-strucutral-directive.component.html. First add a button:


<button (click)="onToggleText()">Toggle Text</button>

This button will toggle on and off the custom directive. It’ll call a method inside the component class,
which we’ll review shortly.

Now add the directive that will be shown:


<div *ngIf="!textHidden">
This is hidden text
</div>

This is just a div we will create, and destroy by toggling the value of textHidden, a value we’ll put inside
the Typescript class. We put the ngIf structural directive. Notice that there is an asterisk before the
directive name. This is Angular shorthand. It is turned into an Angular template:
<ng-template [ngIf]="!textHidden">
<div>
This is hidden text
</div>
</ng-template>
The ngIf is put on the ng-template tag, but the contents remain unchanged. This template is stored
behind the scenes and rendered when placed on the page. If you use any variables, directives, or other
Angular expressions within the ng-template they will be rendered when put on the page.

Let’s move over to the use-structural-directive.component.ts class file. First, add the textHidden value:
textHidden = false;

This is a simple Boolean value. Now, add the onToggleText() method:


onToggleText() {
this.textHidden = !this.textHidden;
}

You should be good to run the app:


If you drill down into the HTML of the page in the default state, you’ll see the div containing “This is
Hidden Text” as part of the main display. Of course, the text also displays on the page. Notice the ng-
reflect-ng-if in the HTML with a value of true. This is part of Angular’s internal mechanism for keeping
track.

Now click the button:


The div with the text is nowhere to be seen, it is vanished from the page and from the HTML. Notice the
ng-reflect-ng-if bindings object has been reset to false, as part of Angular’s internal mechanism.

Creating Your own Structural Directive


For the purposes of this sample, I’m going to recreate the ngIf directive with a key differentiator. I’m
going to make a hasAccess directive, that that you may use as part of a security or permission system in
your app. Instead of using a condition as the input I’m going to input an array of user roles. The
directive will determine if the user has access to this specific content, and if not remove it.
First, create a component to demonstrate our new structural directive:
ng generate component create-structural-directive

You’ll see something like this:

Then, open the app/app-routing.module.ts file to add a route:


const routes: Routes = [
{path: 'sample1', component: UseAttributeDirectiveComponent},
{path: 'sample2', component: CreateAttributeDirectiveComponent},
{path: 'sample3', component: UseStructuralDirectiveComponent},
{path: 'sample4', component: CreateStructuralDirectiveComponent},
{ path: '**', redirectTo: '/sample1'}
];

I added a sample4 route that points to our new component.

Now let’s create the directive:

ng generate directive directives/has-access


You’ll see something like this:

I’ll get to the directive in a bit, but first let’s create a service to contain user information:
ng generate service services/user-service

You should see something like this:

Open up the service code:


import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserServiceService {
constructor() { }
}

We’re going to do a few things to the service. First, we’re going to add some constants to represent
user roles. Next, we’re going to create an active user property. This service will be injected into the
directive and will be used to compare the active user’s roles with the roles for the specified element.

First, add the constants:


export const ADMIN = 1;
export const AUTHOR = 2;
export const DELETER = 3;
export const EDITOR = 4;

I put these in the service class, but above the metadata. There are four roles:

• Admin: A user who will have access to everything


• Author: A user who can create new items.
• Deleter: A user who can delete items.
• Editor: Someone who can edit existing items
Now add an activeUser property as part of the service class. I’m going to implement this as a get and
set method:
private _activeUser: {userId: number, roles: number[]};
get activeUser() {
return this._activeUser;
}
set activeUser(value) {
this._activeUser = value;
}

In a real application I would create a class type for the user object, for this sample I’m keeping it simple
and defining the expected object definition in-line. There is a special reason why I’m implementing this
as a get and set method. I want to dispatch an event whenever the value changes. Add the event
emitter:
userChange: EventEmitter<any> = new EventEmitter();

Then loop back to the set method:


set activeUser(value) {
this._activeUser = value;
this.userChange.emit(value);
}
Now whenever the user changes, the directives can listen for this event and add or remove items as
needed.

Now switch over to the has-access.directive.ts file:


import { Directive } from '@angular/core';
@Directive({
selector: '[appHasAccess]'
})
export class HasAccessDirective {
constructor() { }
}

First, let’s inject three services into the constructor:


constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private userService: UserServiceService
) { }

The templateRef is a reference to the template that this directive will create or delete. The
viewContainer is a reference to the parent container of the directive. The UserServiceService will be
used to reference the roles of the currently active user.

Now, we want to keep track of the appHasAccess value, which will be an array of possible roles:
private _allowedRoles: number[];
@Input('appHasAccess')
get allowedRoles() {
return this._allowedRoles;
}
set allowedRoles(allowedRoles: number[]) {
this._allowedRoles = allowedRoles;
this.onChange();
}

Roles are integers, so I made the allowedRoles property an array of numbers. I use the Input() alias to
use the name, appHasAccess as the directive, but use the name allowedRoles inside the directive code.
There is a method named onChange(), which you’ll use to encapsulate the changes that must take place
when either the activeUser changes in the userService or when the value of the directive changes.

Let’s build the onChange() method. It starts out like all other methods:
private onChange() {
}

Add an allowAccess variable:


let allowAccess = false;
This value will be used to determine whether we display or remove the template associated with this
directive. It is defaulted to false, because for security purposes it is better to hide something in error
than to show it in error. Now do some checking:
if (this.userService.activeUser) {
allowAccess = this.userService.activeUser.roles.some((userRole) => {
return this.allowedRoles.some((allowedRole) => {
return allowedRole === userRole;
});
});
}

If there is no activeUser, then we skip the check. Otherwise we check, leaving allowAccess as false
value. The check makes use of the array some() function, which is shorthand for looping over all the
items in the array and comparing two values. We use one some() inside the other in order to compare
the user’s roles to the allowed roles for this directive’s instance. If at least one value is equal, then the
allowAccess will be set to true.

The rest of the method code creates, or removes, the templateRef on the viewContainer:
if (allowAccess ) {
if (!this.created ) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.created = true;
}
} else {
this.viewContainer.clear();
this.created = false;
}

The viewContainer creates an instance of our template using the templateRef if the user is allowed
access to it. Alternately, if the user does not have access to the code, the viewContainer clear() method
is called to delete the component..

Notice I have a created flag in the directive. Create it now as an instance variable on the class:

created = false;
This will come into play when changing the active user or the directive elements. If the values change,
but the component is already created, we do not want to create it again.

Finally, we want to call this onChange() method when the userChange event is dispatched from the
service. Inside the directive’s constructor, listen for it:
this.userService.userChange.subscribe((value) => {
this.onChange();
});

Our directive is complete, so let’s move onto the CreateStructuralDirectiveComponent component in


order to put together a sample to demonstrate this in action. Let’s start with the HTML, create-
structural-directive.component.html. First, I’ll add some radio buttons to allow us to switch between
profiles:
<h1>Role Switcher</h1>
<input type="radio" name="user" (click)="selectUser(0)"> Admin<br>
<input type="radio" name="user" (click)="selectUser(1)"> Author<br>
<input type="radio" name="user" (click)="selectUser(2)"> Deleter<br>
<input type="radio" name="user" (click)="selectUser(3)"> Editor<br>
<input type="radio" name="user" (click)="selectUser(4)"> Author and Editor<br>
<input type="radio" name="user" (click)="selectUser(5)"> Author and Deleter<br>
<input type="radio" name="user" (click)="selectUser(6)"> Editor and Deleter<br>

A click from any one of these will execute a selectUser method inside the component; and each
selection represents a different user with different permissions.

Let’s create a menu, each one referencing a different profile type.:


<h1>Menu</h1>
<ul>
<li *appHasAccess="[ADMIN]">Admin Only Link</li>
<li *appHasAccess="[AUTHOR]">Author Only Link</li>
<li *appHasAccess="[DELETER]">Deleter Only Link</li>
<li *appHasAccess="[EDITOR]">Editor Only Link</li>
<li *appHasAccess="[AUTHOR, EDITOR]">Author and Editor Link</li>
<li *appHasAccess="[AUTHOR, DELETER]">Author and Deleter Link</li>
<li *appHasAccess="[EDITOR, DELETER]">Editor and Deleter Only Link</li>
</ul>

The appHasAcesss directive is put on the li tags with the asterisk. The value passed in is an array with
some number of roles inside it. The directive will know to compare the input values with the values
from the currently activeUser and remove or display the specific list items.

Now look at the create-structural-directive.component.ts file so we can put this all together:
import { Component, OnInit } from '@angular/core';

@Component({
selector: 'app-create-structural-directive',
templateUrl: './create-structural-directive.component.html',
styleUrls: ['./create-structural-directive.component.css']
})
export class CreateStructuralDirectiveComponent implements OnInit {
constructor() { }

ngOnInit() {
}
}

This is a currently a standard placeholder component. First, let’s copy the role constants into local
template variables so that they can be accessed in the view:
ADMIN = ADMIN;
AUTHOR = AUTHOR;
DELETER = DELETER;
EDITOR = EDITOR;

Next, let’s create an array of different user profiles:


userProfiles = [
{userId: 0, roles: [ADMIN]},
{userId: 1, roles: [AUTHOR]},
{userId: 2, roles: [DELETER]},
{userId: 3, roles: [EDITOR]},
{userId: 4, roles: [AUTHOR, EDITOR]},
{userId: 5, roles: [AUTHOR, DELETER]},
{userId: 6, roles: [DELETER, EDITOR]},
];

Each object in this array coincides with a radio button in the main view. Be sure to inject the
userServiceService into this component so that we can change the activeUser:
constructor(private userService: UserServiceService) { }

Finally, implement the selectUser() method:


selectUser(index) {
this.userService.activeUser = this.userProfiles[index];
}

When a radio button is selected in the HTML view, this method will be called, which will change the
activeUser in the userService, which will dispatch a userChange event which will cause the directives
onChange() method to run, removing or adding items from the menu list.

Run the code:


With no user selected, nothing is shown in the menu. Take a look at the HTML:
You see the place holder for the templates, and the ng-reflect-allowed-roles binding shows the values
of each directive, but no HTML templates have been added because no user is selected and nothing was
activated.

Now select the Admin user:


You see the single menu option which is for admins only, but nothing else.
Looking at this, you see most of the directive bindings have not changed, but the admin only li is now
generated on the page as HTML.
Now try one of the compound roles:

This displays more things, including all author links and all editor links. Review the HTML here:
A lot more HTML is added to the page, as relevant based on the code inside the directive. This proves
that are new structural directive is creating, and deleting HTML from the DOM.
Final Thoughts
When building Angular applications my first thought is to always create a component, because that is
the base building block of an Angular application. But, when you want to apply some functionality to
any given component or HTML element, a directive is a really good way to do that.
Chapter 3: Debug Applications from Your Browser
When writing code in any language it is important to understand the tools available to you to help you
debug. This article will talk about some of the ways you can debug your code, first by simply outputting
data to your web browser console, and second by using a JavaScript step-through debugger.

Use Outputs and Alerts


Sometimes you just want to see the state of a variable at a certain time during your application’s run.
This allows you to make sure that proper functionality flow is happening and that values are getting
properly updated. I used outputs extensively while building the LearnWith Task Manager application.

To give you an example of this, I’m going to turn to the login.component.ts file from the LearnWith app.
A user tries to login by clicking a login button. The login button executes the onLogin() method. Add a
line to the method like this:
console.log('onLogin');

The console.log() statement will output some text, “onLogin”, to your browser’s web developer console.
In most browsers you can bring up the web developer console using F12. What this does is show you
that your button is properly hooked up to the method. Sometimes this is the first step you need to verify
when debugging your code.

Next, the method performs some validation to look for errors. The original implementation of the
method would do this:
if(errorFound == true){
alert(this.usernameError + '\n' + this.passwordError);
return;
}

If an error was found, then an alert would be displayed to the user and the processing of the method
would stop with the return. Eventually, the alert was replaced with displaying errors directly on the
HTML form, which is better user experience. However, the alert was a great first step that could be
used to prove that validation was working properly.

After input validation, the onLogin() method is to execute the authenticate() method in the
AuthenticationService object. This method creates a parameter object to pass into the remote service.
You can output the object to the console:
console.log(parameters);

Attempting to login has two console outputs and a single alert. Load the main LearnWith app, and click
the login button without entering a username or password. You’ll see this:
The Chrome developer console will look like this:

The second console.log() statement, displaying the parameters object, never ran because there was an
error detected, and the return statement prevented the method execution from continuing.

If I enter a username and password, then click login again, this is what the console will look like:
You see the onLogin() method, and then the parameter string is output to the console. After that, you
see a few log statements from the login success method. The result object returned from the server is
output to the screen. You see the arrow next to the object; that means you can drill down into the
object’s contents to examine what is there. The object returned from the server has two properties: an
error property and a resultObject property. The embedded resultObject property is another object,
representing the user who logged in. The other two options you see on the screen are both ‘__proto__’.
These relate to JavaScript’s Object-Oriented model, which uses prototypes instead of classes, but is
beyond the scope of this book.

When I started doing JavaScript in the mid-1990s, using alerts was a very common debugging technique.
Unfortunately, alert boxes interrupt the application processing flow and make the user dismiss the alert
box before they can continue to use the application. This is fine if your intent is to provide the user with
feedback that they can’t ignore. For debugging information, that is less than ideal. The console.log()
statements are superior because they do not interrupt the application flow and do not require input
from the user to continue. You could also, theoretically, leave them in for deployment without affecting
the users of the application.
Review the Network Tab
Sometimes you want to review the network calls that pass between your user interface and your server.
Many browsers provide this feature built in as part of their web developer tools, and they are all similar.
I want to take a deeper look at the Chrome tools which I use daily. This is the Chrome network tab when
loading the login page for the LearnWith Task Manager application:

It tells you the file that was loaded; the type of request; the results of the request and what file made
the request; and even what line of the file initiated the request. It also gives you the file size and the
time it took to load the file. Although not obvious in the above screenshot the Waterfall can give you a
good feel for how your page loads:
The red line shows where the page was fully loaded. Before the red line you see the length of time it
took for the specific file to load. After the red line you’ll often see a lot of templates and service calls
made by the Angular libraries, since Angular setup does not start until after all the pages and libraries
were downloaded. Roll over one of the options to see more details:

This tells you what time the request was sent; how long it took to download and how long it waited to
download. This is interesting information if you are trying to debug network issues that may cause long
app load times.

You can use the console to drill into specific details of a request. Just click the file in the network console
and the details are brought up. Here is the request that is used to authenticate the user:
On the right side you see all the details. The form parameters that were sent are in the form data
section. You can also see details on the response:

The preview tab shows the results; in this case it gives you a JSON object you can drill into. The response
tab will give you similar data:
If you are ever having problems with your service calls not working; this is a great way to drill down into
the requests to help diagnose the problem. You can also use this tool to find out if your page is loading
invalid files, or files from the wrong path. Sometimes one typo in a path name will prevent items from
loading and break your whole application.
Use a Step Debugger
I find one of the most useful debugging tools is a step through debugger. Step through debuggers allow
you to add breakpoints to code and to manually execute each line so you can review variables and other
values. Most browsers have a JavaScript debugger built in to the browser as part of their web developer
tools, but for the sake of this article I will focus on the Chrome debugger, because it is the one, I use the
most.

To use the Chrome debugger, first open the web developer tools and then click on the source tab:

The source screen of Chrome developer tools has a tabbed list of files. In the screenshot above, I have
two TypeScript files shown, the login.component.ts and the authentication.service.ts. Even though the
browser won’t run the TypeScript directly, our use of map files allows us to review the TypeScript code.
On the right side of the screen are a bunch of different options, such as watch expressions, breakpoints
and other sections.

To the left of the login.component.ts you see a button that kind of looks like a play button from a tape
deck. Click it to open up the files view:
This panel shows you the location of all the files related to the current script. That includes map files,
source files, compiled JavaScript files. It even shows some libraries that were loaded. The ng:// section
contains a lot of the Bootstrap components and the HTML templates. You can use this browser to open
files not already open. The button on the top right side of the screen can be used to open or close the
panel on the right side of the original screenshot.

The main benefit of a debugger is to be able to stop code execution at certain points in code to review
the code and step through the code manually. The spot where the code stops is called a breakpoint. You
can add a breakpoint by clicking on the line number next to a segment of code:

You see in the screenshot that the breakpoint is now highlighted in blue, and the breakpoint shows up in
the breakpoints section of the right panel. I put the breakpoint in the first line of the onLogin() method.
This method is executed when the use clicks the login button of the login screen of the LearnWith
application.

Click the login button, and the execution will stop:


The current line that the code is executing is highlighted in the left. On the right you can see the call
stack, which contains the series of calls that executed to get to the current line. The elements in the call
stack relate to the Angular framework.

You can also see scope variables, which are all the variables that are defined, and accessible from the
current method. Here is a more expanded, detailed, version of the scope variables section:
The local variables are defined in the method, and some such as errorFound have not been defined yet.
The Closure section relates to specific functions available to the method. For example, the
authentication_service_1 is the Angular function that created the AuthenticationService object which
was injected into the component. The global section refers to a lot of globally accessible variables.

Above the scope, call stack, watch sections you’ll see a row of buttons that allow you to control how the
debugger works:

Icon Description
Resume: After execution is stopped at a specific breakpoint, this button will continue
execution for the current line.

Step Over: This button continues onto the next line in the current script, ignoring any
other function calls

Step Into: This continues onto the next executing line. If the next line is in another
function, then the code will jump into that function.

Step Out: This button will continue onto the next line of executing code after the current
function call completes. Sometimes I’ve seen this button called “step return” because it
immediately returns the results of the function call back to whatever piece of code asks
for it.

Deactivate Breakpoints: This button is a helper button that will deactivate all
breakpoints. I use this most commonly during an application start up procedure when I
don’t want to step into the debugger until the user is ready to start interacting with the
application.

Pause on Exception: This button tells the debugger to immediately stop execution when
the JavaScript code has an error. This can be helpful when you’re trying to diagnose
errors, or when you come up with errors you didn’t even know existed. This button has
three different states; to pause on no exceptions, to pause on all exceptions, and to
pause on uncaught exceptions.

Most of the buttons in the table should be familiar to you if you’ve used a debugger with other
technologies.

Another important aspect of a step through debugger is the ability to set up watch expressions. The
watch expression section is in the top right of the window tree. In this window you can specify any
expression you wish, and see the results. Here is the watch window with a few watch variables:

I added a simple watch expression, which displays the value of the errorFound variable. Then I added
two conditions, one for errorFound== true and the other for errorFound == false. The watch expression
will show the results of the expression. Click the plus sign on the right of the header bar to create a new
watch expression; then type the expression or variable into the input at the bottom of the watch pane.
You can create expressions of any type you need, but mostly I just enter variable names.
Debugging Angular with Augury
Augury is a chrome browser plugin that allows you to introspect an Angular application. At times I find it
useful to use when debugging Angular applications. This section will tell you bit about it.

Install Augury
You can install Augury, just like any other Chrome Browser Plugin. Go to the Augury listing in the
Chrome web store, click the “Add to Chrome” Button and you’re off. Load an Angular application, such
as the Learn With application you built in the books and you’ll see this:

There are three tabs to Augury:

• Component Tree: The component three shows a list of all components in the current view and
how they relate to each other.
• Router Tree: The router tree will give you information about the current route.
• NgModules: The NgModules tab lists all NgModules in the application and their related
dependencies.

Look at NgModules
Open up the NgModules tab. This is the least interesting tab:
What is good about this one is that you can see all the modules in your applications, as well as their
providers, exports, declarations. This is primarily intended as a reference. It can be helpful if you’re
trying to figure out where that service is coming from, or if you remembered to declare your new
component.

Review the Component Tree


Let’s click over to the component tree. Select the AppComponent in the left pane of it:

The left side contains a list of all components used in the current view. This drills down and shows the
hierarchy, including the text inputs inside the login component. The right side contains details about the
component. In this case we see that the AppComponent has a single instance variable, title, with a
value of ‘task-manager’. We can click right into the source’s components if we want to open it up in the
source pane.

Click on the Injector graph:


This does not give us a lot of information because the AppComponent is the main root component of
the application and is not injecting a lot.

Let’s select the LoginComponent. First look at the properties:


]

This is more interesting because it includes the services we injected, such as the router and the
userModel. We can drill into those to find out the properties available to use from the service. It also
includes all the properties inside the component. This is a great way to see the current state of the
component and it can help you debug things especially state related bugs.

Click over to the InjectorGraph for the LoginComponent:


This shows you the current component and the services injected into it. It can be helpful when trying to
deal with an undefined service error. Roll your mouse over one of the injected services:
This is useful information to have, especially in larger applications with multiple modules. It lets you get
at the source of your services.

I want to show you how complex things can get. Login into the app, and drill down into the
DataTablesComponent:

You can see the full structure of the application’s main screen on the left side including our custom
components, forms, inputs , and select boxes. The right side shows the dependencies in the
DataTableComponent including what services are injected and at what level they are injected. This can
be useful when debugging larger applications.

Look at the Router


Click over to the router tab:
This parallels the routes defined in the applications routing module:
const routes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'tasks', component: TasksComponent, canActivate: [AuthGuard] },
{ path: '', redirectTo: 'login', pathMatch: 'full' },
{ path: '**', redirectTo: 'login' }
];

The main AppComponent contains the router-outlet, and injects the information from all these other
routes into that spot. You can mouse over one of the routes to get more info:

The data property in the popup would refer to a route resolver, something we did not use in the main
book, but is a way to load data or run other code before the view loads.

Making use of Augury can be a helpful debugging tool when you are trying to introspect the state of
your app’s components and to fix the reason why things are going wrong.
Final Thoughts
You should be ready to use these tools to debug your JavaScript application. We discussed using
console.log() or alert to output information to the browser. It showed you how to use the Chrome’s
network tab to view the requests that the browser sends to the server. Finally, it taught you the
concepts behind using Chrome’s JavaScript debugger. The debugger is perhaps the most important tool
when debugging application. There are even ways to integrate browser debuggers into IDEs, such as
IntelliJ; however, that is beyond the scope of this book. I looked at Chrome, but most modern web
browsers have similar debugging features for web developers.
Chapter4: Using Redux with Angular
The JavaScript ecosystem is full of a lot of frameworks and libraries that you can tie together to create
your Application. One of the more popular frameworks is Redux, which is used for managing state.
Redux is most commonly associated with React but ngrx exists as an Angular implementation too. This
chapter will give you an overview of Redux, an example of how to use the library, and then show you
how to use ngrx to implement Redux within an Angular application.

Understanding Redux Terminology


Many frameworks have their own terminology, so this section will explain some common terminology
with Redux.

• Actions: Actions are a collection of data that you send to the Store. The object must have a type
value to define the type of action. The action in Redux is similar to the EventEmitter you’ve
probably used in your Angular applications, and are passed to the store using a dispatch()
function.
• Action Creators: Action Creators are functions that return an action. Action Creators do not
dispatch the action, only return it. It is a way to encapsulate your functionality for creating an
action.
• Reducers: Reducers are a function that update the state of the application. It accepts the
current state, and the action you are performing. Reducers should be pure functions, meaning
they do not have any side-affects such as changing the arguments or calling non-pure functions.
The reducer does not change the current state of the application because that would be a side
effect. It only creates, and returns, a new state object.
• State: The state is an object that stores data for your application, such as items in a shopping
cart, the user who logged in, or other information.
• Store: The store is a single object that holds all the application state. It can return the state
using a getState() function. It registers or unregisters listeners using a subscribe() function. And
it updates state via dispatch() function.

As we progress through this chapter, we’ll cover each item in more detail.

Understanding Redux Flow


Redux has a unidirectional data flow. That means that data always flows in one direction throughout
the app. I put together a diagram:
Let’s look at each box:

1. Start in the top middle. You have a view which is waiting for action. This could be a user
entering data or clicking a button. Technically this doesn’t even have to be a view but could be
any code in your app, such as the result handler of a remote service call.
2. When an action occurs, the view will call the dispatch() method on the store and send in the
action object.
3. The store will, in turn, call the reducer() function. The current state and the new state are
passed in as arguments. The reducer function will do some magic and return the app’s new
state.
4. The store saves the new state.
5. Then the store calls any listener functions. At some point your code must have called
store.subscribe() so it could get notified when something changed.
6. The listener functions run code and update the view. If they need access to the current state
they can call the getState() method on the store.

The process is simple to understand.

Create a Vanilla JavaScript Sample


I’m going to show you how to create a sample using Vanilla JavaScript. We’re going to create a simple
Hello World style sample. In a real app, you’ll use Redux in conjunction with another framework such as
Angular or React, but when learning something new like to focus on one thing without other
complications. This sample will avoid the complexity of CLIs and build scripts.

Set up the Infrastructure


Create a new HTML Page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redux Vanilla JS</title>
</head>
<body>

</body>
</html>

First import the Redux library:


<script
src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.0/redux.min.js">
</script>

Instead of using NodeJS and Build Script tools, I’m just pulling it out from an Internet based CDN because
it is the simplest way. Create the reducer:
<script>
function reducer(state, action) {
}
</script>

The reducer is the function that will run when actions are dispatched to the store. It takes in the current
state and the action, then runs code to determine what the new state will be. A reducer should not
have any side effects. That means it should not modify the existing state. The first step is to make a
copy of the existing state:
var newState = Object.assign({}, state)

On first run of the application, no existing state will be defined, so we’ll check for that and set some
defaults:
if (typeof state === 'undefined') {
newState = {
helloUser : ''
}
}

The state of the application is just a JavaScript object. I included one property on that object, helloUser
and defaulted it to an empty string. Once we start dispatching events, we’ll revisit this function to
handle those event types. Until then, just return the new state:
return newState;

That completes the reducer, for the moment.

Now, create the store:


var store = Redux.createStore(reducer);
This calls the createStore() value on the Redux library. The reducer() function is passed in. Notice we
are saving the store as a local variable for future reference. Do not put this line of code inside the
reduce.

Let’s create our simple UI:


Enter Your Name: <input id="username"><br/><br/>
Hello <span id="helloValue"></span>

We’re going to set this up so that when the user types in the input, the text will automatically update in
the span. I’ve seen similar samples used to demonstrate how binding works in Angular.

Let’s switch back to JavaScript and create a function to render the UI:
function renderHello() {
document.getElementById('helloValue').innerHTML =
store.getState().helloUser.toString()
}

The renderHello() function accepts no arguments. It uses the JavaScript document object and
getElementByID() function to retrieve the helloValue span. Then it populates it with the helloUser
string in the state. We retrieve the state from the store using the getState() functionality. Be sure to
call the renderHello() function immediately to render the function in the default state:
renderHello()

Whenever the state changes, we want to run this renderHello() function. We do that with the
subscribe() function on the Redux store:
store.subscribe(renderHello)

Now, when the state changes, the renderHello() function will be called, thus causing the UI to update.

Whenever the username input is modified, we want to dispatch an action to the store so that the
reducer() function runs, which will return the modified state, and then run the renderHello() listener to
modify the UI. This is the code:
document.getElementById('username').addEventListener('keyup', function (e) {
store.dispatch({ type: 'NAME_MODIFIED', value : e.target.value})
})

Without a framework, such as Angular, it is a bit complex to listen for events on elements, but we grab
the username input with getElementByID() and then listen for the keyup event. We use
store.dispatch() to send a NAME_MODIFIED action. By convention, the type of the action is a constant
put in all caps, but here we are hard coding it a bit.

We need to modify the reducer() function to handle the NAME_MODIFIED action:


switch (action.type) {
case 'NAME_MODIFIED':
newState.helloUser = action.value
break;
default:
// do nothing
}

This code is after the undefined check, and before the return statement. It is a switch statement that
checks for the action’s type, and does actions based on that. At this stage in the application, we only
have a single event, but we’ll add one more as we iterate over this code.

You should be able to run the code now:

As you type your name the text will appear after the hello.

Saying Goodbye
With every hello comes a goodbye. We are going to create a button that will say goodbye to the user,
and then clear out the helloUser value from the store. The purpose of this sample is to add more
objects in the store.

First, let’s start with the UI:


<button id="goodbyebtn">GoodBye</button><br/><br/>
GoodBye <span id="goodbyeValue"></span>

I added a goodbye button, and a span for the goodbyeValue. Back to the JavaScript, handle a click on
the goodbyebtn:
document.getElementById('goodbyebtn')
.addEventListener('click', function (e) {
store.dispatch({ type: 'NAME_LEFT',
value : store.getState().helloUser})
})

This dispatches an action. The type is NAME_LEFT. The value is the current helloUser.

Let’s go back to our reducer function and add some code to handle this new action:
case 'NAME_LEFT':
newState.goodbyeUser = action.value;
newState.helloUser = '';
break;

It is just another case statement in the switch. We set a new value on the state to goodbyeUser and set
the helloUser value to an empty string. When we set the default, near the beginning of the reducer()
method, be sure to initialize the goodbyeUser state property:
if (typeof state === 'undefined') {
newState = {
helloUser : '',
goodbyeUser : ''
}
}

Now we need to create a function to render the code:


function renderGoodbye() {
document.getElementById('goodbyeValue').innerHTML =
store.getState().goodbyeUser.toString()
}

This just uses getElementByID() to get the span for the goodbyeValue. It sets the innerHTML to the
stores goodbyeUser property. Make sure you subscribe:
store.subscribe(renderGoodbye)

The code should be runnable now:


Enter your name and you’ll “Hello Jeffry”, just as with our original sample. Then click the GoodBye
button, and you’ll see the name populate after Goodbye and the name after Hello blank out. I did not
add code to blank out the user input, but you should be able to do that easily if needed.

Define an Initial State


I want to modify our code a bit to define an initial state. Technically we already do that inside the
reducer, like this:
if (typeof state === 'undefined') {
newState = {
helloUser : '',
goodbyeUser : ''
}
}

This can be simplified with some code tweaks. First, define the initial state:
var initialState = {
helloUser : '',
goodbyeUser : ''
}

Now change the reducer method signature:


function reducer(state = initialState, action) {
We’re using syntax shorthand to define the default argument if state is undefined. Try to run things
again, and the app should work.

In a real-world app, I’d probably create the state as its own class, and pass a new instance of the state
into the method as the default argument. Such details are not needed for this proof of principle.

Split up the Reducer


State objects and Reducers can get very complex in a real-world application. What do we do to make
them simpler? What we’re going to do is create a reducer for each section of the site and then combine
them into our one big reducer function.

Let’s start by creating a reducer for the hello portion of this app:
function helloUser(state = '', action){
var newState = state;
switch (action.type) {
case 'NAME_MODIFIED':
newState = action.value;
break;
case 'NAME_LEFT':
newState = '';
break;
default:
}
return newState
}

I created a new function named helloUser(). Notice that this function is named the same name as the
state property. This is done on purpose, and you’ll find out why in the next section. This function has a
similar signature to the reducer. It accepts a state and an action. However, it does not accept the full
state object. We’ll send in the specific value for the helloUser state, which is just one branch of the
main state object. This reducer function only focuses on handling its own state, not other states.

The helloUser() reducer only operates on the helloUser state variable. Notice it defaults the newState
to an empty string in the command line signature. We might do something more complex if we were
using an object or other data type. This reducer has to handle both major actions. If the name is
modified, it sets to the new name. If we said goodbye to the user, then the helloUser resets to an
empty string.

Create a goodbyeUser() reducer:


function goodbyeUser(state = '', action){
var newState = state;
switch (action.type) {
case 'NAME_LEFT':
newState = action.value;
break;
default:
}
return newState
}

This reducer only needs to operate on the goodbyUser state. As with the helloUser reducer, and as
such only needs to respond to the NAME_LEFT action. In that case, it takes the value from the action
and sets it to the new state. The NAME_MODIFIED state is ignored here.

Now, create the actual reducer:


function reducer(state = initialState, action) {
return {
helloUser: helloUser(state.helloUser, action),
goodbyeUser: goodbyeUser(state.goodbyeUser, action)
}
}

This automatically returns an object, representing the new state. The helloUser property is given the
results of the helloUser() reducer. The goodbyeUser property is given the results of the goodbyeUser()
reducer. Run the app and you’ll see it working.

Using the combineReducers( ) function


In the previous sample we split up the reducer and manually called our sub reducer functions. Redux
provides a short hand to make that happen in the form of a combineReducers() function. Replace the
reducer with this:
reducer = Redux.combineReducers({
helloUser,
goodbyeUser
})

Redux will automatically know how to combine these reducers. Try the app again, and you’ll find that it
works.
Using ngrx
The ngrx library is an implementation of Redux that is used for Angular applications. I’ll recreate the
previous sample using Angular and ngrx to show you how it all comes together.

Setup the Application


For this sample I’m going to use the Angular CLI. If you do not have it installed, you can find
samples on the web site. After you have that setup, run
ng new redux-sample

This will setup the new, default, Angular application inside the redux-sample directory:

Switch to that directory


cd redux-sample

And now ngrx store


npm install @ngrx/store

You’ll see something like this:


There are a few different aspects to the ngrx library, but we’re focused on the store for the purposes of
this article.

Create Your Actions


Create a class for your actions. We had two actions in the app:

• NAME_MODIFIED: This action manes the user input is modified, and we change the “Hello
Name” text in the app’s display.
• NAME_LEFT: This action means we say goodbye to the person. The “Goodbye Name” is
changed and the “Hello Name” is deleted.

In our vanilla JavaScript example, we did not create individual classes here the actions, but it makes
more sense to do so in a real application. I put both actions in a single class:
import {Action} from "@ngrx/store";

export const NAME_MODIFIED = "NAME_MODIFIED";


export const NAME_LEFT = "NAME_LEFT";

export class NameAction implements Action {


type: string;
value: string;
}

I put this class in a name.action.ts file at app/actions/.

Create your Reducer


Next create the reducer file. The reducer is the function that processes the dispatched action and
returns the new application’s state. I created the file reducer.ts in the app/reducers directory.

First, import the actions:


import {NAME_LEFT, NAME_MODIFIED, NameAction} from "../actions/name.action";

Then, I’m going to create an interface for the state:


export interface helloGoodByeState{
helloUser : string,
goodbyeUser : string
}
In a bigger app, I might put the interface in its own file, but I’m trying to keep things simpler for this
sample. Also create a default state:
const initialState : helloGoodByeState = {
helloUser : '',
goodbyeUser : ''
}

Finally create the reducer:


export function reducer(state : helloGoodByeState = initialState,
action: NameAction) {
var newState = Object.assign({}, state)
switch (action.type) {
case NAME_MODIFIED:
newState.helloUser = action.value
break;
case NAME_LEFT:
newState.goodbyeUser = action.value;
newState.helloUser = '';
break;
default:
// do nothing
}
return newState;
}

This reducer mirrors what we previously created in the vanilla JS sample. It accepts two arguments, the
state and the action. The state is set to the initialState value if passed in as null. A copy of the current
state is created, because the reducer will never modify the existing state, it will always return a new
state. Finally, there is a case statement, which is used to change the helloUser and goodbyeUser values.

Now open up the app.module.ts file. First import the StoreModule:


import {StoreModule} from "@ngrx/store";

Also import the custom reducer we just created:


import {reducer} from "./reducers/reducer";

As part of the import section of the @NgModule metadata, load the StoreModule:
imports: [
BrowserModule,
AppRoutingModule,
StoreModule.forRoot({ hello : reducer}),
],

This uses the forRoot() syntax that is common when loading one module into another. It accepts a
single object, which is our state object. It contains a single property, named ‘hello’ and its value is the
reducer function.
While we’re in here, let’s add Angular’s FormModule. First, import it:
import {FormsModule} from "@angular/forms";

Then add it to the imports:


imports: [
BrowserModule,
AppRoutingModule,
StoreModule.forRoot({ hello : reducer}),
FormsModule
],

We’ll use this when creating the form to collect the user’s name.

Modify the AppComponent


Now let’s modify the default view. We’ll start with the TypeScript. Open up the app.component.ts file
in the app directory, and you’ll see something like this:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'redux-sample';
}

First get rid of the title variable in the AppComponent, then add some imports:
import {select, Store} from "@ngrx/store";
import {Observable} from "rxjs/index";
import {NAME_LEFT, NAME_MODIFIED} from "./actions/name.action";
import {helloGoodByeState} from "./reducers/reducer";

There is a lot to dissect here. First, we bring in the Store and select from the ngrx library. The store is a
service used to access the store. The select is a function used to retrieve an element from the store.
Observable’s should be a known quantity by the time you’re reading this, so there is no need to expand
on that. We also bring in our two actions and the interface for the state. We’ll use all of these in the
code.

Now let’s move to the AppComponent class. Let’s create some variables:
nameInput : string;

The nameInput will be used to collect the user’s input for the first name. We want to say hello to this
person.
goodByeOutput : string;
The goodByeOutput value will be used to store the last person we said goodbye to. It will be an
argument into the NAME_LEFT event.
storeReturn : Observable<any>;

The storeReturn will contain a reference to the store and will be an Observable that we can subscribe to
update our values.

Let’s look at our constructor:


constructor(private store: Store<helloGoodByeState>) {
this.storeReturn = store.pipe(select('hello'));
this.storeReturn.subscribe( r =>{
this.goodByeOutput = (r as helloGoodByeState).helloUser;
})
}

The constructor uses Angular’s dependency injection syntax to inject the Store service into the
component. That gives us access to the store. Then we use select() to get a specific value out of the
store—hello in this case. The hello property references the property we defined when we set up the
reducer in the main NgModule. The select() returns an Observable that we can use in the class, or the
view, to retrieve the store’s current state. We subscribe to it next, using it to update the goodByeOut
value.

Let’s create our two event dispatchers. First onNameChange():


onNameChange(){
this.store.dispatch({
type: NAME_MODIFIED,
value : this.nameInput
});
}

This function dispatches the NAME_MODIFIED event, whenever the name input is changed. We use
store.dispatch() to tell the store that the event has changed, and ngrx will call the reducer under the
hood to update the app’s state, which will trigger our observable. I did not create a specialized Action
Creator for this sample but would probably do so in a more advanced setup. The value passed to the
event is the input that the user entered for the name.

Now, look at the


onGoodbyeClick(){
this.store.dispatch({
type: NAME_LEFT,
value : this.goodByeOutput
});
}

This acts similarly to the onNameChange() method. It calls store.dispatch() to tell the store that an
event occurred. The event type is NAME_LEFT, and the value is the goodByeOutput variable. We are
updating goodByeOutput whenever the helloUser variable is updated.
Create the View
Open up the app.component.html file in the app directory. Delete everything in there so you’ll have a
blank file. First, create the input box for collecting the name input from the user:
Enter Your Name:
<input id="name" [(ngModel)]="nameInput" (keyup)="onNameChange()">
<br/><br/>

The ngModel is used to tie the input’s value to the nameInput class variable. And the keyUp event is
used to run the onNameChange() function, which will in turn dispatch an event to the store.

Output the ‘Hello User’ value next:


Hello {{(storeReturn | async)?.helloUser}}
<br/><br/>

We output the storeReturn using the async pipe. The async pipe is used to handle the Observable in the
view. Since the storeReturn is an object, we use the question mark operator to drill down into the
helloUser property if we the object is returned. Without this we would get a runtime error when
storeReturn is null.

Next, add the GoodBye button:


<button id="goodbyebtn" (click)="onGoodbyeClick()">GoodBye</button>
<br/><br/>

There is nothing special here, when the button is clicked, the onGoodbyeClick() method in the class is
executed. Finally, display the goodbyeUser, as returned from the state:
Goodbye {{(storeReturn | async)?.goodbyeUser}}
<br/><br/>

You should be good to test the app now.

Run the App


Run the app at the console:

Launch this in a browser:


Enter some text in the input and you’ll see the Hello message immediately updated:
Click the Goodbye button:

The app is working as expected.


Combing Reducers with ngrx
The problem with our previous implementation is that having one big reducer will complicate a large
app. In the Vanilla Redux portion, we reviewed the ability to combine multiple reducers into a single
unit. We can do something similar using ngrx. This section will iterate over the previous sample.

Create the Reducers


There are two aspects to our application, saying hello and saying goodbye. We’ll create a reducer for
each piece of functionality. Open the reducers file in the app directory and delete the current reducer.
Now, create a reducer for handling the helloUser state. The helloUser state will represent the input the
user typed, which is a simple string:
export function helloUserReducer(state : string = '', action: NameAction) {
var newState = state;
switch (action.type) {
case 'NAME_MODIFIED':
newState = action.value;
break;
case 'NAME_LEFT':
newState = '';
break;
default:
}
return newState;
}

Remember the input into this is not a full state object, but just one piece ofe the state. Since the
helloUser state is a simple string, this method just checks for the event type and sets the value
according. If we are processing the NAME_MODIFIED event, we set the new name. If we are processing
the NAME_LEFT event, we clear the name by setting it to an empty string.

Let’s do the same for the goodbye piece of the state. Here is the goodByeReducer() function:
export function goodbyeUserReducer(state : string = '', action: NameAction) {
var newState = state;
switch (action.type) {
case 'NAME_LEFT':
newState = action.value;
break;
default:
}
return newState
}

The goodByeUser() state is also a simple string. It only changes for the NAME_LEFT event, where we
give it the value of the event action.

Modify the AppModule


With two new reducers created, let’s set them up in the main module. Open app.module from the app
directory. First, import them:
import {goodbyeUserReducer, helloUserReducer} from "./reducers/reducer";

Then modify the import section of the @NgModule metadata:


StoreModule.forRoot({
helloUser: helloUserReducer,
goodbyeUser: goodbyeUserReducer
}),

Previously, we gave the single reducer a name, and then introspected the object. Now we are using
multiple reducers, each with its own name. When modifying the view code, we’ll have an easier time
because we’re returning simple values instead of having to introspect an object.

Modify the View


Open up the app.component.ts file. First, we’ll modify the variables:
nameInput : string;
goodByeOutput : string;
nameReturn : Observable<string>;
goodbyeReturn : Observable<string>;

The nameInput and goodByeOutput values are set up identically to the previous sample. The
storeReturn observable is replaced with nameReturn and goodbyeReturn.

Now move to the constructor:


constructor(private store: Store<helloGoodByeState>) {
this.nameReturn = store.pipe(select('helloUser'));
this.nameReturn.subscribe(r =>{
this.goodByeOutput = r;
});
this.goodbyeReturn = store.pipe(select('goodbyeUser'));
}

The method signature has not changed, and the store is still injected into the component. We use the
store service to select the helloUser value. By subscribing to that we save the goodByeOutput value for
the NAME_LEFT event. The goodbyeReturn value is selected using the goodbyeUser slice of the store.

Let’s turn our attention to the app.component.html file modifications. The name input does not need
to change:
Enter Your Name:
<input id="name" [(ngModel)]="nameInput" (keyup)="onNameChange()">
<br/><br/>

The “Hello User” text does change:


Hello {{nameReturn | async}}
<br/><br/>

Since the store select is now returning a string value instead of an object, we don’t have to drill down
into it to get our value. We still need to use the async pipe, because nameReturn is still an observable.
The Goodbye button does not need tochange:
<button id="goodbyebtn" (click)="onGoodbyeClick()">GoodBye</button>
<br/><br/>

The “Goodbye User” text does change:


Goodbye {{goodbyeReturn | async}}
<br/><br/>

The changes here are similar to the “Hello User” changes. We now have a single piece of the store,
goodbyeReturn that returns the string value we need. As such we don’t need to introspect the store
object to get the specific value.

Retest the App


Retest the app you’ll find similar results to our previous sample. The code behind may have changed but
the output has not. Enter some text in the input and you’ll see the Hello message immediately updated:

Click the Goodbye button:


The app is working as expected.

Final Thoughts
Having a global store for your application, and a single point of reference for your application’s state is a
cool idea that I’d love to see implemented more in applications. However, at the time of this writing, I
find the documentation on ngrx sorely lacking, and I feel I barely touched on the surface of the library. I
focused this article on the store, but there are other related libraries—just very little information on
what they are or what they’d be used for. I’m not sure I could recommend using it in a project, due to
the lack of tutorials or documentation.
Chapter 5: Standalone Components
Angular 14 introduced the concept of a stand-alone component. A stand-alone component is one that
does not need a module. These are designed to help simplify the boiler plate when building Angular
applications, and to make them more accessible to users.

Create Your first Standalone Component


To start with, I created a new Angular 15 project with the Angular CLI. From there, I ran my first
command:
ng generate component view1 --standalone

We’re asking the Angular CLI to generate a component named view1. You’ve seen this before if you got
this far in the series, but let’s dissect each section of the command:

• ng: This is the Node hook to the Angular CLI.


• generate: This is the command you send to the Angular CLI to tell it to create some entity.
• component: This referrers to the type of entity you want the angular CLI to generate.
• view1: This is the name of the component you want to create.
• --standalone: This parameter tells the Angular CLI to generate a standalone component, not a
normal component. This is the new flag.

Run this command and you’ll see something like this:

This response is pretty common from generating other components, but you will notice that the main
app.module.ts file is not updated. This is because standalone components do not need to be added to
the module.

Let’s look at the generated component code. First, open the src/app/view1/view1.component.ts file:
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
selector: 'app-view1',
standalone: true,
imports: [CommonModule],
templateUrl: './view1.component.html',
styleUrls: ['./view1.component.css']
})
export class View1Component {
}

Let’s take a look at the configuration object in the @component annotation:

• selector: This specifies how we’ll use the component in a view. You’re used to this from
traditional components.
• standalone: This is a new property that tells Angular that this component is a standalone
component. The value is true or false. I believe it is false by default. We can also use this new
flag on directives and pipes, in addition to components.
• Imports: This is a new property for components, and it is modeled after the same property on a
module. This specifies the other dependencies that this component has. By default we’re
importing the CommonModule, which contain the fundamentals of the Angular framework.
You may need to import other sub components here that you want to use.
• templateUrls: This is legacy and specifies the HTML template that belongs to this component.
Traditional components already use this property.
• styleUrls: This is an array of related CSS files that belong to this component. This one is also
legacy and you should be familiar with it.

Three other files were created. The view1.component.css will start out as an empty file. The
view1.component.spec.ts is a testing file, and we’ll loop back to it later in this article. The
view.component.html is the template file:
<p>view1 works!</p>

It is as simple as you’d expect.


Using the Component
Now that we’ve created the component, how do we add it to a view? Our main application is still
module based, so we have to import it into the module. Open up app.module.ts:
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Add the View1Component to the import list:


imports: [
BrowserModule,
AppRoutingModule,
View1Component
],

And be sure to import it:


import {View1Component} from "./view1/view1.component";

Now, open up the app.component.html file, remove all the default contents, and add it:
<app-view1></app-view1>

Run the development server:


ng serve

You should see something like this:


This isn’t different than what you’re used to seeing at the command line.

Point your browser over to localhost:4200:

Congratulations! You’ve created your first standalone component.

What surprised me about the learning is that the main module still exists, and it is required that you
import the component to use it. It looks like the component just moved from the declarations to the
imports section. There is a way to load an application without specifying a main module, which I’ll cover
later in this chapter.
Using Multiple Components
Let’s jump into a sample where multiple standalone components work together. One of my favorite
examples when demonstrating components, is to create one component that modifies a piece of data
and another component that displays it. I’m starting this sample with a brand-new project, creating
using `ng new`.

First, let’s generate the view component:


ng generate component display --standalone

You should see something like this:

This component will accept a single input, and display it in the view template.

Let’s look at the component default state. Open the display.component.ts file
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
selector: 'app-display',
standalone: true,
imports: [CommonModule],
templateUrl: './display.component.html',
styleUrls: ['./display.component.css']
})
export class DisplayComponent {
}

Inside the class, add an @input property:


@Input() valueToDisplay: string = '';

Don’t forget to update the imports:


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

Now, pop open the display.component.html file:


<p>display works!</p>

Replace all of this with:


{{valueToDisplay}}

This component should accept an input, an display it. Super simple!

Now, let’s generate a component to edit a value:


ng generate component edit --standalone

You should see this:

Let’s take a look at the first:


import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-edit',
standalone: true,
imports: [CommonModule],
templateUrl: './edit.component.html',
styleUrls: ['./edit.component.css']
})
export class EditComponent {
}

For simplicity, we’re going to use ngModel to attach an input to a variable, and to do that we need to
import the FormsModule. In the old school way, we’d do that as part of an angular module, but here
we can add it directly to the imports config of the component:
imports: [CommonModule, FormsModule],

Don’t forget to import it into the class:


import {FormsModule} from "@angular/forms";

Now let’s add a variable:


valueToEdit: string = '';

And an output event:


@Output()
valueToEditChanged: EventEmitter<string> = new EventEmitter<string>();
I named the output event valueToEditChanged, to mirror the valueToEdit. Make sure to add the
imports for Output and EventEmitter:
import { Component, EventEmitter, Output } from '@angular/core';

Open up the edit.component.html file and you’ll see this:


<p>edit works!</p>

Replace it with this:


<input type="text"
[(ngModel)]="valueToEdit"
(ngModelChange)="onValueChange()">

Just a single input of the type “text”. It uses ngModel with double binding to keep track of the
component. It also uses the ngModelChange event to make a call to an onValueChange() method.
Switch back to the edit.component.ts file to create the method:
onValueChange() {
this.valueToEditChanged.emit(this.valueToEdit);
}

This method simply dispatches the event, passing in the new value.

We’ve created two components, be sure to import them both into the app.module.ts:
imports: [
BrowserModule,
AppRoutingModule,
DisplayComponent,
EditComponent
],

And don’t forget your TypeScript imports:


import { DisplayComponent } from './display/display.component';
import { EditComponent } from "./edit/edit.component";

We’re almost ready. Now we open up the app.component.html file. Delete all its contents, and load in
our two components:
<h1>Edit</h1>
<app-edit (valueToEditChanged)="display.valueToDisplay = $event"></app-edit>

<h1>Display</h1>
<app-display #display ></app-display>

First comes the edit component. It listens to the valueToEditChanged event and runs an in-line
function. The inline function makes a change to the display component, tweaking the valueToDisplay
property. The display component doesn’t have any formal properties set, however I did give it the name
display using the #display syntax.
I’m setting up the component communication in the HTML for simplicity in this sample. Normally I try to
avoid adding any sort of business logic—even simple logic--in the HTML, because it makes things harder
to test.

Go back to your console, run ng serve and take a look at the browser:

The default state has no typed in text, and therefore no display text. Start typing and you should see the
display automatically update:
All good!
Using Providers
Providers, or services as they are sometimes called, are a way to share code across multiple components
in an Angular application. Stand Alone Components support them just as well, and I want to rework the
previous sample to use a provider instead of the input property and output event.

First create the service:


ng generate service shared

You should see something like this:

The service is generated:


import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class SharedService {
constructor() { }
}

By default, the service is created to be injectable in the root, which means we do not have to set it up in
a module, or at an individual component level. Both traditional components, and standalone
components allow for the provider metadata to be set up at the component level.

Let’s add a single property to this SharedService:


value: string = '';

Now switch over to display.component.ts:


export class DisplayComponent {
@Input() valueToDisplay: string = '';
}

Remove the input, and add a constructor:


constructor(public sharedService: SharedService) {}

The constructor users Angular’s dependency injection to inject the shared service into this component.
Don’t forget the TypeScript import:
import { SharedService } from '../shared.service';

Now open display.component.html:


{{valueToDisplay}}

That references the variable we just deleted, so replace it with a reference to the variable inside the
sharedService:
{{sharedService.value}}

Now let’s go over to edit.component.ts:


export class EditComponent {

valueToEdit: string = '';

@Output() valueToEditChanged: EventEmitter<string> = new


EventEmitter<string>();

onValueChange() {
this.valueToEditChanged.emit(this.valueToEdit);
}
}

We define a property to hold the value to be edited. We have an output event, and a method to deal
with changes. This is no longer needed for this sample, so delete them all. Add a constructor:
constructor(public sharedService: SharedService) {
}

The constructor injects the SharedService using the same dependency injection approach the
DisplayComponent used. And we need the same import:
import {SharedService} from "../shared.service";

Now pop open edit.component.html:


<input type="text" [(ngModel)]="valueToEdit"
(ngModelChange)="onValueChange()">

We deleted the valueToEdit, so the ngModel reference needs to be changed. Also, we no longer need
the ngModelChange event handler:
<input type="text" [(ngModel)]="sharedService.value">

The ngModel was pointed at the property directly in the SharedService.

Finally, go back to the app.component.html:


<h1>Edit</h1>
<app-edit (valueToEditChanged)="display.valueToDisplay = $event"></app-edit>
<h1>Display</h1>
<app-display #display ></app-display>

In this case, we’re listening to the valueToEditChanged event on the EditComponent and using that to
modify the valueToDisplay in the display component. None of this is needed since both components
are sharing a reference to the same service, so we can clean this up:
<h1>Edit</h1>
<app-edit></app-edit>

<h1>Display</h1>
<app-display></app-display>

No run ng serve on your console and point your browser to localhost:4200:

The default state has everything blank. Start typing:


An update in the input box of the EditComponent is automatically reflected in the DisplayComponent.

I know this second iteration of the same example looks like a lot less code, but I always like to caution
people about relying on global services, as they hinder our ability to reuse that component. Reusability
is not always a concern, but you have to be cognizant of the tradeoffs your making with your
architecture decisions.
How to use Embedded Standalone Components
It is very common in a real-world app for one component to be nested inside another. Can we do this
with standalone components? Absolutely! Let’s create a new component that wraps our display and
edit components. For this, I’m going to continue to iterate over the previous sample.

Let’s start by creating a standalone wrapper component:


ng generate component wrapper --standalone

It’ll look like this:

Let’s open up the wrapper.component.ts:


import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-wrapper',
standalone: true,
imports: [CommonModule],
templateUrl: './wrapper.component.html',
styleUrls: ['./wrapper.component.css']
})
export class WrapperComponent {
}

We want to import our other two stand alone components as part of the Component annotation
configuration object:
imports: [CommonModule, DisplayComponent, EditComponent],

Be sure to import the classes for TypeScript:


import {DisplayComponent} from "../display/display.component";
import {EditComponent} from "../edit/edit.component";

Now, open the wrapper.component.html:


<p>wrapper works!</p>

Delete all this, and replace it with what we had added to the app.component.html previously:
<h1>Edit</h1>
<app-edit></app-edit>

<h1>Display</h1>
<app-display></app-display>

Now, let’s open the app.component.html file, and you’ll still have the above. Replace it with this:
<app-wrapper></app-wrapper>

Let’s open up the app.module.ts file. Previous we had imported the DisplayComponent, and
EditComponent as part of the module:
imports: [
BrowserModule,
AppRoutingModule,
DisplayComponent,
EditComponent
],

However, we no longer need to do that, since they are only used as children to the
WrapperComponent, so let’s remove those and add the Wrapper:
imports: [
BrowserModule,
AppRoutingModule,
WrapperComponent
],

Don’t forget about the TypeScript import:


import { WrapperComponent } from './wrapper/wrapper.component';

From here, we should be able to re-run the code and see this working. Point your browser at
localhost:4200 after restarting your dev server:
Start typing and see the updates:
I’m starting to feel a bit guilty about reusing screenshots here, but you’re not paying for printing by the
page, so I think we’re good.
Component Level Services
In the previous example we are still using a shared service between the two components, but the
service is set up at a global level. Open up the shared.service.ts file:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class SharedService {
value: string = '';
constructor() { }
}

It is the providedIn configuration in the Injectable metadata that tells Angular to load the service
globally. However, the service is only being used by children of the wrapper component, so we don’t
need to define it globally. Let’s define the provider as a provider as part of the wrapper component,
which should share it with all its children—even the standalone components.

First, remove the providedIn metadata from the service:


import { Injectable } from '@angular/core';
@Injectable()
export class SharedService {
value: string = '';
constructor() { }
}

Now, jump over to the wrapper.component.ts file. As part of the component metadata, add in a
provider:
@Component({
selector: 'app-wrapper',
standalone: true,
imports: [CommonModule, DisplayComponent, EditComponent],
templateUrl: './wrapper.component.html',
styleUrls: ['./wrapper.component.css'],
providers: [SharedService]
})

In earlier versions of Angular we would have to define the providers at the module level always. I’m not
sure when they allowed for component level providers, but I like it a lot of services which are used to
share data across multiple components that make up a single screen.

Restart your Angular CLI dev server and load it in the browser. Type in the input and you’ll see the
output continue to update, even with this minor code restructure.
Routes and Lazy Loading
My favorite use case of stand-alone components is to lazy load elements through the router. In the past,
if we wanted to lazy load a component or section of an app, we’d have to point it to a module. You’d
have to do something like this:
const routes: Routes = [
{
path: `subsection`,
loadChildren: () => import(`./subsection/subsection.module`).then(
m => m.SubsectionModule
)
}
];

The module would have to load all components, providers, and could even include it’s own router. I
always found this to be a lot of boilerplate code just to implement lazy loading. Now with a standalone
component, we can make it simpler, which I love.

First, let’s create a simple routes that does not include lazy loading. Open up the app-routing.module.ts
file:
const routes: Routes = [
{ path: 'view1', component: WrapperComponent },
{ path: '**', redirectTo: 'view1' }
];

The first route is named view1, and points to WrapperComponent. I also added a catch all route,
distinguished by the two asterisks in the path. The catch all route redirects to the view1.

Now, open up app.component.html:


<app-wrapper></app-wrapper>

Remove this and replace it with the router outlet:


<router-outlet></router-outlet>

With this approach, we can remove the component import from the app.module.ts. Instead of this:
imports: [
BrowserModule,
AppRoutingModule,
WrapperComponent
],

We can just do this:


imports: [
BrowserModule,
AppRoutingModule
],
Recompile the app, and load it in the browser:

You can see the route in the browser at view1. Start typing to make sure it all works:

All good to go; so, we’ve proved that the stand-alone components are working fine with the router. But,
the use of the router here mirrors what we did in the main books, which did not investigate lazy loading
at all. How do we set up lazy loading of the module?

Back to the app-routing.module.ts and replace the view1 route with this:
{
path: `view1`,
loadComponent: () => import(`./wrapper/wrapper.component`).then(
m => m.WrapperComponent
)
},

The syntax is very similar to the lazy loading segment I shared earlier. Instead of a loadChildren()
method, we now use a loadComponent() method. The value is an arrow functions. The arrow function
uses the import command to load in the component. The import returns, surprisingly, a promise. We
resolve the promise with the then() method, and the result handler returns the component.

You can re-run the app right now to see that it is continuing to work, but to see the real power of lazy
loading, let’s create another route and view. Let’s create a new component:
ng generate component view2 --standalone

You’ll see something like this:

We’re not going to implement a lot of functionality in the View2Component, only using it to link
between the two respective views. Take a look at the default view2.component.ts:
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-view2',
standalone: true,
imports: [CommonModule],
templateUrl: './view2.component.html',
styleUrls: ['./view2.component.css']
})
export class View2Component {
}

To tell Angular to link between routes, we’ll need to load in the RouterModule as part of the imports
configuration:
imports: [CommonModule, RouterModule],

And don’t forget the TypeScript import:


import {RouterModule} from "@angular/router";

Open up view2.component.html. Replace all the contents with a link back to View1:
<a [routerLink]="['/view1']">Goto View1</a>

For View2Component that’s all we need.

Let’s go back to View1 which is powered by WrapperComponent. First, we’ll need to tell it about the
RouterModule in the component config imports:
imports: [CommonModule, DisplayComponent, EditComponent, RouterModule],

Don’t forget the TypeScript import:


import { RouterModule } from '@angular/router';

This is the same as what we did in the View2Component. We’ll made a similar addition in the
wrapper.component.html:
<a [routerLink]="['/view2']">Goto View2</a>

I added a link to view2 in front of the other two components in the WrapperComponent.

Now, open up the app-routing.module.ts. I’m going to show you the two cases, and how the browser
interacts differently. First, with no lazy loading setup:
const routes: Routes = [
{
path: 'view1', component: WrapperComponent
},
{
path: 'view2', component: View2Component
},
{ path: '**', redirectTo: 'view1'}
];

Run the app, and take a look at the network console:


Click in the browser between the two views and you’ll notice nothing changes in the network tab.
Everything is loaded all at once.

Now, let’s switch back to lazy loading in the app-routing.module.ts:


const routes: Routes = [
{
path: `view1`,
loadComponent: () => import(`./wrapper/wrapper.component`).then(
m => m.WrapperComponent
)
},
{
path: `view2`,
loadComponent: () => import(`./view2/view2.component`).then(
m => m.View2Component
)
},
{ path: '**', redirectTo: 'view1' }
];

We’ve already explored the view1 route and the catch all redirect route. This includes a view2 route,
which loads the View2Component. Now reload the app in the browser and review the network tab:
We load most of the same files. One thing you’ll notice is that main.js is a lot smaller. And there is also a
an additional js file loaded, which corresponds to the WrapperComponent. The end result is that we
have less data loaded on the initial app load—which means your users are using the application much
quicker.

Click over to View2:

I didn’t clear out the network tab before clicking, but primarily you see View2Component loaded, but
not until we clicked on the link to load that view.

It is beyond the scope of this article to go into the benefits and specifics of lazy loading, but let’s just say
I love this use case for stand-alone components, because it is something that clearly removes a lot of
boilerplate.
Bootstrap an Application without using a Module
The default application for an Angular CLI is still to put everything within a module, but that is no longer
required using standalone components. I’m going to continue iterating over the previous sample, and
this is going to be rough. First delete the app.module.ts and app-routing.module.ts. I’m serious, it’s
okay to do that even if it violates everything you know about building Angular applications. It made me
uncomfortable too.

Open up the app.component.ts file:


import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'New';
}

We want to make this a standalone component. First, add the standalone flag:
@Component({
selector: 'app-root',
standalone: true,
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

We’ll need some imports here too, so import the RouterModule, which is needed to support the router-
outlet in the app.component.html view:
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterModule],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

Don’t forget the TypeScript import:


import { RouterModule } from '@angular/router';

Now open up the main.ts in the src root:


import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
This is used to bootstrap the module, and the module specifies the root location. That’s not want we’re
doing today, delete all of this code. We aren’t bootstrapping a module, we’re bootstrapping an
application:
bootstrapApplication(AppComponent)

Conveniently we do this with the bootstrapApplication() method. You’ll want to import this from the
platform-browser package that is part of Angular:
import {bootstrapApplication} from '@angular/platform-browser';

And we’ll also need to import the main AppComponent:


import {AppComponent} from "./app/app.component";

This is a good start, but you’re probably wondering how we define the routes; which were previous
done in their own module using RouterModule.forRoot({). An alternate option has been provided for
standalone components now, using a provide function, in this case providerRouter(). We can set up
providers as part of a config object in the bootstrapApplication() function:
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
]
});

You can use this providers array to set up other providers, if need be. Be sure to import the
providerRouter() function:
import {provideRouter, Routes} from "@angular/router";

While we’re at it, I imported the Routes type. One thing we’re missing is defining the routes. Previously
they were defined inside the app-routing.module.ts, but with that gone I added them directly to
main.ts:
export const routes: Routes = [
{
path: `view1`,
loadComponent: () => import(`./app/wrapper/wrapper.component`).then(
m => m.WrapperComponent
)
},
{
path: `view2`,
loadComponent: () => import(`./app/view2/view2.component`).then(
m => m.View2Component
)
},
{ path: '**', redirectTo: 'view1' }
];
These routes are copied verbatim, with no changes, from the old routing module.

Now rerun the app with `ng serve` and point your browser to localhost:4200:

Your WrapperComponent loads fine, it’s two sub components are loaded and typing in the input proves
that the output works and the two components communicate through the service.

Switch over to view 2:


This is the boring one, but it works. You can also check the network tab to see that the lazy loaded
views are properly loading on demand:

This whole approach is interesting to me, and I suspect in the near term we’ll see a mix of stand alone
components used against traditional module components, but I’m not sure what the future of Angular
holds.
Testing a Standalone Component
I don’t have a lot of functionality in my components to provide a deep dive into testing. For that, see
the other book that has a full chapter dedicated to that exclusively. But, I did want to share how the
tests for standalone components are set up.

Let’s dissect the display.component.spec.ts file. First the imports:


import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DisplayComponent } from './display.component';

If you’re like me, you notice that the TestBed is imported, which you’ll remember is used to configure
modules. At least right now, testing modules are still use to test standalone components.

Next is a describe block and some variables:


describe('DisplayComponent', () => {
let component: DisplayComponent;
let fixture: ComponentFixture<DisplayComponent>;

These two will work together to provide us with an instance to the component.

Now, there is a beforeEach():


beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ DisplayComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(DisplayComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

The TestBed is used to create a module, and the component is listed in the imports section—not the
declarations. This mirrors what we saw when using standalone components earlier. A component is
created the fixture is grabbed; then from there we get the componentInstance. Finally, we trigger
detectChanges() on the fixture to start the component’s redraw cycle.

Next we have a test:


it('should create', () => {
expect(component).toBeTruthy();
});

This is a simple default test to validate the component’s existence. Finally, we close out the describe
block:
});

If you’ve done testing with Angular Component classes before, very little is new here.

Try running the tests:


ng test

And you’ll see a slew of errors:

Let’s tackle them one by one. The first error, shown above, is because we converted the AppComponent
to a standalone component, but never modified the tests. Open up app.component.spec.ts and find
where the testing module was configured:
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();

We need to move the AppComponent from the declarations to the imports. And we can delete the
declarations since there is nothing left in it:
await TestBed.configureTestingModule({
imports: [
RouterTestingModule, AppComponent
],
}).compileComponents();

Rerun the tests and check out the next error:


We never set up the SharedService as a provider for the DisplayComponent. Let’s do that. Open up
display.component.spec.ts and find where the testing module is configured:
await TestBed.configureTestingModule({
imports: [ DisplayComponent ],
providers: [SharedService]
})
.compileComponents();

I added providers to the array. Also do the TypeScript import:


import { SharedService } from '../shared.service';

If you think two steps ahead of me, you probably realized we’ll have to do the for the EditComponent.
Open up edit.component.spec.ts and find the same module setup:
await TestBed.configureTestingModule({
imports: [ EditComponent ],
providers: [SharedService]
})
.compileComponents();

And in this file you’ll want to import the SharedService with the rest of the TypeScript imports:
import { SharedService } from '../shared.service';

Rerun the tests, and at least we’re getting fewer errors, but they aren’t gone yet:
This error tells us that the SharedService tests do not know how to find the SharedService provider.
This is because we removed the providedIn root config option on the service class. As such we need to
specify the class as a provider in the testing module. Open up shared.service.spec.ts, find the testing
module creation and add the providers array:
TestBed.configureTestingModule({
providers: [SharedService]
});

Check the tests again:

One of the fun things with writing code without updating the tests as you go is that you run into a lot of
errors. To fix this one, we’ll need to import the RouterTestingModule into the WrapperComponent’s
test module. Open up wrapper.component.spec.ts:
await TestBed.configureTestingModule({
imports: [ CommonModule, WrapperComponent, RouterTestingModule ]
})
.compileComponents();

Be sure to load the TypeScript imports for both the CommonModule and the RouterTestingModule:
import { CommonModule } from "@angular/common";
import { RouterTestingModule } from '@angular/router/testing';

We’ll need to do the same setup for the View2Component, so open up view2.component.spec.ts:
await TestBed.configureTestingModule({
imports: [ CommonModule, View2Component, RouterTestingModule ]
})
.compileComponents();

You’ll need the same two imports:


import { CommonModule } from "@angular/common";
import { RouterTestingModule } from '@angular/router/testing';

Double check the tests, we’re almost done:

This last failure is actually a failing test and not a config issue. Open up the app.component.spec.ts and
find the test:
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent)
.toContain('New app is running!');
});

This test fails correctly. It checks for values in the rendered template, but we changed those values. You
can delete this test entirely from the file. Now everything should run successfully:
I hope you learned something from this exercise. The important piece is that testing of a standalone
component is currently done through a testing module, but you import the component instead of
declaring it. It sounds a bit non-intuitive, so I wonder if they’ll find a new way to do this in the future.
Final Thoughts
I learned a lot writing this chapter, and I hope you learned a lot reading it. I’m not sure how I feel about
standalone components yet, but I do see them as a one way to make Angular applications easier to
build, especially around lazy loading. I also see a lot of potential using them in libraries, where you want
to optimize a component for reuse.
Afterword
I wrote this series to document my own learning process building HTML5 applications. The main series
focuses on building an application from start to finish. This book focuses on all the surrounding concepts
you’ll probably need to know on the job. I hope you benefited from this book.

If you enjoyed this book, we invite you to post a review on Amazon.com. Reviews help independent
authors like me because Amazon uses the number of reviews as a factor to help us show up in their
search results.

If you want more information, be sure to check out www.learn-with.com. You can test the application
we created in this book, get the source code for each chapter, get the most up to date version of the
books, and browse some of our other titles which build the same app using different technologies.
Check out the other bonus books to this series, along with some of the screencasts we have released.

If you need personal mentoring or have a custom consulting project, we’d love to help out, so please
reach out.

Send me an email at jeffry@dot-com-it.com and tell me how this book helped you become a success.

You might also like