1. News Flash

03-12-2019
  • Released version v2.14.2

2. Release notes

v2.14.2 (03-12-2019)
  • Fix an error in the link to the site of Angular.io (modify http:/[]angular.io to http:/[/]angular.io)

v2.14.1 (14-05-2019)
  • Mention that installation of TypeScript is done through the angular cli installation process so no manual install of TypeScript anymore

  • Fix the link to the Angular CLI. Changed to http://cli.angular.io

v2.14.0 (09-05-2019)
  • Remove the Topic: in the Topics since it is double mentionning (like white snow?)

  • Rename title Modifying to Create a method

  • Add setting to pom to have selectable source code WITHOUT that annoying linenums

  • Change [source, javascript] to [source, javascript, linenums, options="nowrap"]

  • Rename some get methods which return a list to list() since the name should be more clear on this method

  • Add topic: Observable ⇒ Pipe

  • Add how to upgrade TypeScript

  • Add more explaination regarding what the --routing option does when creating angular app with $ ng new …​

  • Explain the selector attribute of the @Component annotation more thoroughly after feedback of group

3. Structure of this training

For the summary of Angular see this page Link to Summary

During this training we will handle the following structure per topic
  • Introduce topic

  • Why

  • When

  • How

    • This module explains the theory of installing typescript

  • Assignment

    • This modules lets you practise with the above learned theory

    • Target

    • Roadmap

    • Steps (although not always target, roadmap and steps are applicable)

    • Validation: this module validates that you understood this topic well enough and validates that your assignment is OK

  • Solution: this module shows a possible solution if applicable

  • Conclusion

Sometimes there is some more or less to mention since now every topic might have the question: when to do it …​ And sometimes there is no assignment applicable. In the end only wisdom counts :-)

4. Conventions of this document

Showing code vs showing Shell commands

When showing code which is to be executed in your Windows CMD or Linux Terminal, the "code" will be prefixed with a $ sign like this

Demo Linux / Windows command shell
$ ng generate component User

When showing code Angular (sometimes Java or C#) than the code will not be prefixed with a $ sign like this

Demo Angular code
1
2
3
4
export class User {
        id: Number;
        name: string;
}
Meaning of < around some value >

When expressing the smaller than and the greater than sign around some value, the meaning is that you should replace the value INCLUDING the smaller and larger sign to a value of your choice, or a value which is applicable at that moment. e.g

$ ng new <appName>

or to enable routing directly for later usage (which is better now)

$ ng new <appName>  --routing

can be changed by as example to e.g.

$ ng new myFirstBikeApplication
Using ellipsis (…​)

When there are three periods / ellipsis in some sourcecode in this document it means that there might be some more code in sourceblock on your machine but we are not focussing on that for now

5. Working through the courseware

During this training we will introduce the next part of the Angular framework and start working on it

We will use the same structure as the Tour of Heroes but we will use the link to the Fake REST api of JSON placeholder for convenience and to prevent to get too much in the details of creating a REST api. (which is NOT part of this training)

6. Using the REST service embedded in this course

There is (since 10-10-2018) an embedded REST api using NodeJS in this course which can be downloaded here

Introduction

Hence, in fact a standard REST api with url http://localhost:8081 and endpoint users

Installation
  • Locate a directory where you want to make the REST service

  • cd to it and invoke

  • $ npm init (enter) (and enter the values as is for your convenience or just enter)

  • unzip the files of the zip above to that location (overwriting your package.json)

Configuration
$ npm install
Running
$ node app
Validation

7. Abbreviations

Abbreviations
  • CLI: Command Line Interface

    • The way of working in a DOSBox or Shell (Linux) to express statements

8. Introduction to Angular

8.1. Introduction: What is Angular

Angular is a opinionated framework which allows us to create web-applications using TypeScript

8.2. Why and What is Angular

Why using Angular

There are many front-end JavaScript frameworks to choose from today, each with its own set of trade-offs

Many people were happy with the functionality that Angular 1.x afforded them. Angular 2 improved on that functionality and made it faster, more scalable and more modern. Organizations that found value in Angular 1.x will find more value in Angular 2.

Angular is easi(er)
  • more modern

  • more capable and easier for new programmers to learn than Angular 1.x

  • easier for project veterans to work with

8.3. Why: Features and Benefits

Some features and benefits from http://angular.io

Progressive web apps
  • Use modern web platform capabilities to deliver app-like experiences. High performance, offline, and zero-step installation

Templates
  • Quickly create UI views with simple and powerful template syntax

Angular CLI
  • Command line tools: start building fast, add components and tests, then instantly deploy

The first release of Angular provided programmers with the tools to develop and architect large scale JavaScript applications, but its age has revealed a number of flaws and sharp edges

Angular 2 was built on five years of community feedback

9. TypeScript

To add code to (y)our project we will use the called language TypeScript

9.1. Why TypeScript

We are using TypeScript for several reasons
  • TypeScript is called TypeScript because it is a statically typed language

  • this prevents us from making (too much) runtime errors

  • this helps us during development

9.2. What is TypeScript

TypeScript is the native language of Angular which is even build / made by Microsoft

Hence we are using a Google / Microsoft product when we are using Angular

Angular 2 was written in TypeScript, a superset of JavaScript that implements many new ES2016+ features

By focusing on making the framework easier for computers to process, Angular 2 allows for a much richer development ecosystem

Programmers using sophisticated text editors (or IDEs) will notice dramatic improvements with auto-completion and type suggestions. These improvements help to reduce the cognitive burden of learning Angular 2. Fortunately for traditional ES5 JavaScript programmers this does not mean that development must be done in TypeScript or ES2015: programmers can still write vanilla JavaScript that runs without transpilation.

Installation of TypeScript is done through the installation of Angular using the Angular CLI so we do not have to install TypeScript manually!

9.3. Optional: How to use TypeScript

This module explains the theory of installing typescript

Optional: Install TypeScript

Installation of TypeScript happens by issueing the following command in your terminal

$ (sudo) npm install -g typescript
Use the same command later on during your development to upgrade the TypeScript compiler (e.g. per feb 2019 the Angular 7 install fails if you do not upgrade TypeScript)

After this npm-command we should be able to invoke the tsc command from the terminal

Add code

After installing TypeScript, we can add TypeScript code immediately

Add this to file greeter.ts
function greeter(person) {
    return "Hello, " + person;
}

let user:string = "Jane User"; // this is TypeScript

// document.body.innerHTML = greeter(user);

console.log(greeter(user));
Compile it

After adding code we can compile the greeter.ts file using the tsc compiler

$ tsc greeter.ts

The result of this should be greeter.js

We could run this greeter.js file using our node command or just watch the resulting greeter.js file.

9.4. Optional: Assignment: Install and use TypeScript

Install
$ npm install -g typescript
Validate your version
$ tsc -v

Should print the version of typescript. Now (18-09-2018) the version should be around 3.0.3

Create code (add content to file greeter.ts)
function greeter(person) {
    return "Hello, " + person;
}

let user:string = "Jane User"; // this is TypeScript

// document.body.innerHTML = greeter(user);

console.log(greeter(user));
Compile code
$ tsc greeter.ts

A file greeter.js should be generated

Run the code
$ node greeter.js
$ node greeter
You can ignore the extension .js since node expect the file to be a .js file
Validation
  • You should have seen the message "Hello Jane User" on your terminal and NOT something else and NOT Hello undefined!!!

9.5. Relevant parts of an Angular app

Angular consists of the following parts and architecture which are part of this training
  • Install Angular

    • Install Node(JS) and NPM

    • Install Angular CLI (Command Line Interface)

  • Domain model

  • Component

  • Templates

  • Services (REST clients)

  • Dependency injection

  • Directives

  • Data binding

  • Routing

  • Modules

  • The other cement of the Angular app like

    • package.json

    • …​

10. Install Node and NPM

Since Angular and the Angular CLI depends on

This module explains how to install Node and NPM

10.1. Assignment: Install NodeJS and NPM

10.1.1. Optional!!!: Update NodeJS to the latest release

If you installed Node and NPM a while ago you might/must update. See the link below

11. Install Angular CLI

Since Angular(2+) the framework is switched to using the Command Line Interface to generate the (upcoming) parts of the Angular Framework

So …​ that is why we have to install the CLI

11.1. How: Install Angular CLI

Angular uses the

11.2. Assignment: Install Angular CLI

Installing the Angular CLI is pretty simple. After installing Node and NPM we can invoke the the npm command to install it

Installing CLI
$ (sudo) npm install -g @angular/cli
You run the same commmand (sudo) npm install -g @angular/cli to upgrade to the next version
You run ng update on a project to update that project to the newly version after upgrading

12. Create Angular application

This module describes how we can create an Angular application from scratch

Open the cmd/terminal and cd to a directory of your choice e.g.
  • Windows

    • C:

    • cd \Users\raymond\angular\projects

  • Linux/Apple

    • cd /home/rloman/angular/projects

Now we can invoke commands to create a fresly green angular app using the command: ng new <appName>

or to enable routing which we should do since mostly we will use routing

ng new <appName> --routing

For instance to generate an app for users we might do something like this

$ ng new user-app --routing (enter)

Afterwards, Angular will now have created a directory user-app in the above mentioned location which is a full blown fresh Angular app

You might wonder what that routing option does?, well ⇒
Functionality of the routing option during creation of the Angular app
  • Add an app-routing.module.ts file in your src/app folder where you can tweak the routing in (later)

  • Add AppRoutingModule to imports in src/app/app.module.ts

  • Add <router-outlet> tag to app.component.html

Since Angular CLI 7 the question "Do you want to add routing?" is asked during project creation so you might forget to enter it.

12.1. Explain the result of a generated Angular app

After generating the application structure a lot of files are created. The most important onces will be described below but be aware that some parts are not used perse yet so the learning of this files is an organic process

12.1.1. Most used for starters

package.json
  • The NodeJS file which describes all the Node dependencies for this project. Comparable with Java’s Maven’s pom.xml

package-lock.json
  • File for administering the changes in the package.json (should be commited in git)

index.html
  • The file which is opened by you, the customer when starting the app. The most used and important tag in the index.html is (or should be) the router-outlet (with routing enabled) or app-root (without routing) since that renders all the output of the app

app.module.ts
  • contains the first application module and describes what is available in this appliation

app.component.ts
  • this component is the first component of this app and mostly this is the starting component with it’s HTML when the app starts

app.component.html
  • the HTML which is to be rendered when the app.component will be active

assets folder
  • a folder where we might be adding content later for deployment

environments
styles.css
  • a file used to add styles for the ENTIRE application, not to be confused with the .css files PER COMPONENT

12.1.2. Less used for starters

tsling.json
  • Configuring the TypeScript Lint source code checker

tsconfig.json
  • Configuration the TypeScript compiler

angular.json
  • THE file which is used for administering the project. Especially when you create a new environment (later called Configuration). Not to be used a lot by the (new) programmer

main.ts
  • main.ts is the entry point of your application , compiles the application with just-in-time and bootstraps the application

karma.conf.js
  • The file for configuring the Karma Framework. A framework for testing the Angular application

e2e
  • The filder which contains the End To End Testing apps

12.2. Assignment: Create angular application structure

Follow the next steps to create an angular application structure
$ ng new user-app --routing (enter)

13. Running the created application

13.1. Go to the application

Now we have created a directory user-app, jump into the directuring using the cd command

$ cd user-app

13.2. Run the application

Although the application is now pretty blank, it is possible to run the Angular application now using the Angular CLI command ng serve e.g.

$ ng serve

or to open your default browser directory in the app

$ ng serve --open

At the moment of writing the default HTTP port of an Angular app is 4200 hence we can open an other browser and goto http://localhost:4200

13.3. Stop the application

Although it is not stated when running you can stop the application using Ctrl-C commands.

So when you press Ctrl and keep Ctrl key down and then press C the application will stop runnning

13.4. Running the app explained

When you invoke the command ng serve angular starts to compile your source files to (native) JavaScript and places those files in the _dist/<appName>

If you look at that directory you will see several files

Files in the dist package
  • index.html: the home page of the app

  • main.js: the main JavaScript file

  • map.js files: files which are unused for now. They contain the exported Symbols of the app. Not needed (yet)

You might even copy that files to a public webroot and than you app will run there. e.g.

if you copy that files to c:\users\<username>\apps\bikeshop than you can run the app from that directory

Allthough stated above it is very strange and will not work for remote calls (using REST) since browsers will prevent invoking remote call outside a C: disk website

14. Domain class / model

14.1. Assumptions: Domain class / model

For now the assumption is made that you (yes you, the reader) has learned some regarding Object Orientation so terms like the following below are familiar

Terms
  • class

  • property, field, instance var

  • methods

  • getter

  • setter

14.2. Why: Domain class / model

In several languages so als for Angular it is common best practise and used a lot to express the classes which we are working on during development which are part of the customer domain / problem are created.

This helps us a lot (proven enough) e.g. to speak the same languare in the team and prevents us from making errors

14.3. How: Domain class / model

This module explains how to generate a class in Angular using the Angular CLI

Generating a domain class

You can generate a domain class with the CLI using the following commands

$ ng generate class <className>

e.g. to create a User class we express it like this

$ ng generate class User

The domain class (here 'User') might be expressed using lower case or uppercase

Result

The result of this 'ng generate class' is that Angular will generate a class in 'src/app' folder like this

1
2
3
export class User {

}

We can (later) hack on this class to give it all the properties the User has but for now we will add id:Number and name:string to it (Number and string are bot TypeScript types)

14.3.1. Assignment: Creating domain class

During this assignment we will generate our first domain class

Target
  • To learn how to generate a domain class

Roadmap
  • Since we are using the User domain class later on we will create it now

Steps
  • Perform the following commands on your command line

Generating domain class User
$ ng generate class User
Using your favourite IDE open the project and open the file user.ts in src/app and validate that it contains
1
2
3
export class User {

}

14.3.2. Assignment: Add id and name to domain class User

Using your favourite IDE open the project and open the file user.ts in src/app and validate that it contains
1
2
3
export class User {

}
Add the following to the class User so that it contains
1
2
3
4
export class User {
        id: Number;
        name: string;
}

14.4. Follow-up

After adding the domain class we are ready to continue developing the next step of the application, the Component

15. Component

15.1. Introduction

During this module we will learn what an Angular component is, why we are using it, when to use it and how to use it and finally what the starting content of a Component is

15.2. What: Component

In Angular terms a Component is the part of the application which is responsible for rendering the HTML to the browser. So it is the view part of the MVC model

15.3. Why: Component

The answer to the question why are we using a component? is pretty trivial

Why component
  • High cohesion: the component is ONLY responsible for the view part

  • Loose coupling: we can change the component afterwards without affecting the rest of the applicatoin

  • A frontend developer can focus on component whilst a backend developer on the REST service etc

15.4. Parts of component

When we are generating a Component we will generate three files during generating of the component part

Parts
  • <name>-component.ts contains the view logic

  • <name>-component.html contains the view HTML

  • <name>-component.css contains the CSS

All those parts will become clearer later on

15.5. Generating component

We can generate a component using the Angular CLI using the following syntax: $ ng generate component <componentName>

An example, to create a component which will (later) render a list of all customers might be generated like this

Generate a component
$ ng generate component users

After invoking the above command there will be a file created with the name users.component.ts, users.component.html and users.component.css in the subdirectory src/app_users_

15.6. Assignment

Target
  • to learn how to work with the component generator of Angular CLI

Roadmap
  • During this assignment we will generate our first component

Steps
  • generate component UsersComponent using the following example

Generate component
$ ng generate component users

15.6.1. Validation

  • Validate that the following files are generated in src/app/users

    • users.component.ts

    • users.component.spec.ts

    • users.component.html

    • users.component.css

  • Validate that the following file is modified during generating

    • app.module.ts

15.6.2. Explaination

users.component.ts explained
users.component.ts explained
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'users',
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}
Explaining the above
  • 3: @Component: says that this class is a real Angular component. Hence an annotation, called a decorator in Angular

  • 4: selector: says that we can render this component everywhere in this app when we use the <users>-tag

    • The selector is since the Angular 6 CLI generated by prepending it with 'app-' so when you create a component and that component has a selector 'app-users' then you can use <app-users> everywhere where you want to have the userscomponent rendered

  • 5: templateUrl: directory where the to be render HTML template is located

  • 6: styleUrl: directory where the to be used css file is located

    • for now remember that this file is (only) applicable per component which is handy mostly

  • 10: default constructor with no dependencies yet

  • 12: ngOnInit implementation: the method which is invoked just after the constructor has run

    • still empty for now but later it will fetch the list of users to be shown

users.component.html explained
users.component.html explained
1
2
3
<p>
  users works!
</p>
Explaining the above
  • In fact a still empty component which we will modify later

users.component.spec.ts explained
users.component.spec.ts explained
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { UsersComponent } from './users.component';

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ UsersComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(UsersComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});
Explaining the above
  • For now, all we have and should know is that this file is able to test the behaviour of the Users Component

Explaining the test framework

The users.component.spec.ts file is a unit-test for the Users component. The convention for Angular applications is to have a .spec.ts file for each .ts file. They are run using the Jasmine javascript test framework through the Karma task runner when you use the ng test command

More reading regarding the spec.ts file for now
Explaining the css file
  • for now the css file is still empty

Explaining the change in app.module.ts
Explaining the change in app.module.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { UsersComponent } from './users/users.component';

@NgModule({
  declarations: [
    AppComponent,
    UsersComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Explaing the code above
  • First, we will review this file later on more detailistic

  • For now, this file is the AppModule and describes the AppModule using some decorators

    • 6: Import UsersComponent

    • 11: Declare the availabity of UsersComponent for this (basic) Appmodule

The rest is really for later …​

Table 1. Further reading

Two way data binding in Angular

link:https://blog.thoughtram.io/angular/2016/10/13/two-way-data-binding-in-angular-2.html [, window=_blank]

16. Service

16.1. Why: Service

Components shouldn’t fetch or save data directly. They should focus on presenting data and delegate data access to a Service

Reasons
  • to separate te concerns of developing components and service(s)

  • to abstract the layer between component and service

  • to reuse a service in several other components

16.2. What: Service

A service is the abstraction in Angular which you might see as the waiter in a restaurant. When eating or drinking, the waiter asks what you want and he will deliver it to you.

In Angular a service is responsible for fetching data from a RESTful webservice and giving that data to a Component Or better …​ a Component will ask the Service to get data and when done the component will render the content of his HTML template

In the MVC - pattern you might see a service as the *C*ontroller part of the pattern. But since we are now in the frontend (so everything here is on the View side of the application landscape) the term controller is very confusing, hence they call it the service, since in fact it is the service who is servicing the data from V (Component) to and from M(MOdel)

16.3. How: Service

16.3.1. Caution: Service overhauled

The http / httpClient part of Angular is completely overhauled in Angular5

We will discuss the new way of generating services and make note of the legacy part of Angular service (pre 5) in the last part of this document

16.3.2. Adding Service support

Before we can use the service using the Angular5 way we have to do the following

steps
  • Add an import for HttpClientModule to app.module.ts

  • Add the class HttpClientModule to the imports array in app.module.ts

Some videos regarding this are below in the Resources module

16.3.3. Create a Service

In Angular using the CLI we can generate a Service using the following command

$ ng generate service <serviceName>

hence, to generate a Service for our User domain model we can instruct the CLI like this

$ ng generate service user

NB: Be aware that we are generating a service for the user domain class, hence it’s name UserService. This service will be responsible for every action (Create, List, Fetch one, Update and Delete) for the User model

Assignment: Create service
Target
  • To learn how to generate an Angular service

Roadmap
Steps
$ ng generate service user
Validation

After instructing the command above you should find

two new files
  • src/app/user.service.ts

  • src/app/user.service.spec.ts

Explaination

We will explain the user.service.ts now

Generated code
1
2
3
4
5
6
7
8
9
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class UserService {

  constructor() { }
}
Explaination
  • 1: import Injectable ⇒ to be able to use the Injectable decorator (see below)

  • 3: decorate the class with @Injectable ⇒ So that we can inject the service later as collaborator in an other class e.g. component

  • 4: providedIn: 'root' (explained below)

  • 6: export class UserService which is empty for now

Explaining providedIn

When you add a service provider to the root application injector, it’s available throughout the app. Additionally, these providers are also available to all the classes in the app as long they have the lookup token.

You should always provide your service in the root injector unless there is a case where you want the service to be available only if the consumer imports a particular @NgModule.

16.3.4. Modify a service to fetch data

Assumptions
  • For this module the following knowledge is assumed

    • knowledge of REST

    • knowledge of JSON

As you mentioned the UserService is pretty empty now. We will give the Service more bacon and eggs to fetch data

Let’s start with adding the list method of all Users from the REST api of http://jsonplaceholder.typicode.com

Add list method and consequences
Add the following fields (instance var) to the UserService
  • private url: string = "http://jsonplaceholder.typicode.com";

  • private endpoint: string = "users";

Add the following dependency (using the constructor) to the UserService
 constructor(private httpClient: HttpClient) {

 }
Understand that now we are using the above constructor we created a field or instance variable for the class UserService with type type HttpClient and name httpClient (pretty weird but it rocks)
Add the following method to the Service to get all the users
1
2
3
list(): Observable<User[]> {
    return this.httpClient.get<User[]>(`${this.url}/${this.endpoint}`); // returns an Observable of type User
  }
Explaination
TODO

Assignment and validation and explaination which is here pretty straighforward explain what asynchronous is and that it is widely used (not only in Angular)

16.4. Summary

We just generated a service and made the service salonfahig for fetching data. In the next module we will plumb this newly service to the UsersComponent

17. Plumbing the Service to the Component

NB: I (author) came to the conclusion that code here is better than text :-) So …​ read on …​

Now that we have the service and the userscomponent we have to plumb those

17.1. Modifying the users.component.ts to invoke the service

To do this we have to add a dependency (aka wiring) using the constructor in users.component.ts, following the same principle as wiring the httpClient in the Service.

So to do this we add the following dependency in the users.component

users.component.ts with dependency to service
1
2
3
4
...
constructor(private userService: UserService) {
  }
...
Validate that your imports look like this
1
2
3
import { Component } from '@angular/core';
import { UserService } from 'src/app/user.service';
import { User } from 'src/app/user';
Add the following field to the component
1
private users: User[]; // a field containing an array of User with name users
In the ngOnInit() method execute het following code
    this.userService.list().subscribe(data => {
      this.users = data;
    });
Explaining the code above
  • 1: invoke the userService his get method which returns some data obviously. We subscribe ourself to the data and when the data is received please invoke the arrow function after that

    • So …​ the result of the call is asynchronously placed in the local data variable and …​ 2: than stored in the field users

17.2. Modifying the users.component.html to render the data in users.component.ts

In the users.component.html we now still have to render the users to the browser.

We will handle the simplest case first using an Unorder List using the HTML tag ul and it’s child tag li (List Item)

users.component.html to render the now available users
1
2
3
4
5
6
  <div>
    Exampe list
    <ul>
      <li *ngFor="let user of users">id: {{ user.id }} has name: {{ user.name }}</li>
    </ul>
  </div>
Explaining the code above
  • 1: opening div

  • 2. opening ul

  • 3: li ⇒ opening tag with uses the directive ngFor to say to loop over the users list and use each element as user and print the user.id and user.name to the browser window

  • 3: the so called mustache {{ operator is used to print the content of user.id and user.name

17.3. Modifying the app.component.html to show the users.component.html in his html

Almost done, the only thing we have to do still is to tell Angular through the app.component.html that we will render the users.component when it loads.

Since, after creation, the tag <app-users> is assigned to users.component.html we add the following tag in app.component.html so that it looks like this or contains this

app.component.html
  <p>
          <app-users></app-users>
  <p>

17.4. Assignment

Target
  • To learn how to wire/inject the Service to the component

Roadmap
  • During this assignment you will inject the UserService to the UsersComponent

  • During this assignment you will modify the component to show a list of users

Steps
  • Following the steps above modify the UsersComponent and wire the UserService to the UsersComponent

Validation
Summary

After this module we now know how to generate a component and plumb the the service to the component. Our UsersComponent now shows the list of users. Would n’t it be nice to be able to create a user ?

In the next module we will generate a component and modify our service to create a fresh users, so follow along …​

18. Introduction to Http Verbs

Before diving into the generating of the CreateUserComponent we have to learn how the HTTP protocol is using verbs

Http methods and verbs points merely to the same thing. Me as trainer personally like verb more to distinguish between the Java / .NET method and the Http verbs which is bound to the method

18.1. Why: Http verbs

In the previous module we used the so called GET HTTP verb to show a list of users In the module we explain WHY http has more than only the GET verb

There are more methods than GET alone to use in the http protocol and REST uses it conform a stanard REST convention way

Why would we be using different verbs to express our wanted behaviour
  • To (re) usage a single url and endpoint

  • Because while starting the internet those verbs were already build on so why not use them

  • Because it is clean since we express WHAT we want to do

18.2. What: Http verbs

Http verbs usage for REST
  • GET ⇒ to fetch a list OR to fetch a single element (e.g. one single user)

  • POST ⇒ to create a NEW element, e.g. to create a NEW user

  • PUT ⇒ to UPDATE an element, e.g. to change the name of a user from John to Jane

  • DELETE ⇒ TO DELETE an element, .e.g to delete a user from the list of users

18.3. How: Http verbs

A REST service is build and we assume that we now how in this entire course. But a small recap …​ Since jsonplaceholder.typicode.com uses GET to fetch a list and POST to create a user we have to be able to set the HEADER of the HTTP request to use the Method: GET or POST

Invalid using a browser

Setting GET in the browser (e.g. Internet exploder, Firefox or Mozilla) is simple since it uses it by default, but setting the request method using a browser to POST is impossible hence we can skip this option

Using Postman

There is a application called Postman which every current developer should have installed. It is a so called REST client. Using Postman you can set the request method / verb to GET, POST, PUT or DELETE

Using the verbs in Angular

In Angular the usage of verbs was necessary up till the Angular 5 version. After this version we can use the new HttpClientModule which supports transparent http calls since it has methods for post, get, update and delete in itself and finds the rest out for itself

Since we now know enough of the http verbs we can dive into the real generating of the UserCreateComponent and modifying the UserService to create a User

19. Add create method to UserService

During this module we will modify the UserService to be able to POST a request to the API

19.1. How: Add create method to UserService

The userservice must have a create method for sending out the REST request to the jsonplaceholder.typicode.com url

Using the HttpClientModule we will create the following method in the service to create a user

Add the create method to the UserService
1
2
3
4
5
6
  create(user: User): Observable<User> {
        let resultFromService: Observable<User> = this.httpClient.post<User>(`${this.url}/${this.endpoint}`, user);

        return resultFromService;
    // or shorthand: return this.httpClient.post<User>(`${this.url}/${this.endpoint}`, user);
  }
Explaining the code above
  • 1: Create a create method which expects a User parameter (between parenthesis) and returns an Observable object specific for a User object

    • (we expect the REST backend method to response to us with the newly generated user (with id) and that object is than returned from the backend to our component)

  • 2: Get the result from the REST service (backend) using the URL specified and sending out the newly to be created user als second parameter

  • 4: return the call to the restservice to the component

  • 5: shorthand for line 3 and 5 on one line (which you might or might not prefer)

19.1.1. Assignment: Add create method to UserService

Using the code above of the UserService modify your code to have a create method

Validation
  • For now validation of this assignment is pretty hard. We will see it when we generated the CreateUserComponent which is part of the next module …​

20. CreateUserComponent

During this module we will generate a CreateUserComponent to create users for the application

20.1. Why: CreateUserComponent

Why would we want to make a (separate) component for creating users. The answer to this question lies in the above answered questions, but to recap: to have a single responsible component for one part of the application, to reuse it later and to have a loose coupling.

Hence, the CreateUserComponent is ONLY responsible for creating a user

20.2. What: CreateUserComponent

Our CreateUserComponent will be responsible for creating a user. It will send out a request to the UserService to create a new user

Our UserService will send out the request of the component to the API using a POST request.

20.3. How: CreateUserComponent

To generate a CreateUserComponent we invoke the following command on the terminal

$ ng generate component create-user

After invoking this command, the Angular CLI should have * generated a src/app/create-user/create-user.component.ts file and accompanying .css, .html and .spec.ts file * should have modified the *app.module.ts file which now declarates the CreateUserComponent

Modify the create-user.component.ts to that it contains
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';
import { User } from '../user';

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

  private user: User;

  constructor(private userService: UserService) { }

  ngOnInit() {
    this.user = new User();
  }

  create(): void {
   this.userService.create(this.user).subscribe(user => {
     this.user = new User(); // or call ngOnInit();
   });
  }
}
Explaining the code above
  • 12: a user field to hold the newly created user

  • 14: a constructor to inject the UserService

  • 18: the create method with is a call to the userService and subscribing to the response

  • 20: set the user field to the received data from the Service, this user will be used in the upcoming create-user.component.html explaining

Changing the content of the create-user.component.html

A way to go for creating a user (again …​ a way to go) is using some input tags like this in the CreateUserComponent.html

Content of create-user.component.html
1
2
3
4
5
6
<div>
  <label>id: <input readonly [(ngModel)]="user.id" placeholder="generated id" /></label>
  <label>name:<input [(ngModel)]="user.name" placeholder="name" /></label>

  <input type="button" (click)="create()" value="Create user">
</div>
Explaining the code above
  • 2: a READONLY field for showing the id later

  • 3: a labelled field for typing in the name of the new to be created user

  • 5: the button, when pressed to invoke the create method

Binding explained

In the code above you see some [(ngModel)] parts which are new for you

It means that we are saying to the Angular framework that the user.name is bound to the property user.name in the corresponding create-user.component.ts file (some counts for user.id)

Explaining []
  • surrendering some with [] means that we are using property binding which means that if the property in the .ts file changes, the content of the corresponding input field also changes

Explaining ()
  • surrendering some with () means that we are using event binding which means that if the event or data in the .html file changes, the content of the property in the .ts file also changes

Explaining [()]

Also called banana in the box since we see here with some imagination a banana in a box

It just means that you are using property binding and event binding so both of the mentioned above

This is also called two way binding

20.3.1. Impediment: Adding forms support

Before diving in to the assignment of adding this create-user.component we have to add some to get the code running using the ngModel

Actions to get the ngModel part working
  • modify app.module.ts: import { FormsModule } from '@angular/forms';

  • modify app.module.ts: add FormsModule to the imports sesction

Example of an app.module.ts version
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { UsersComponent } from './users/users.component';
import { HttpClientModule } from '@angular/common/http';
import { UserCreateComponent } from './user-create/user-create.component';

import { FormsModule } from '@angular/forms'; // <==

@NgModule({
  declarations: [
    AppComponent,
    UsersComponent,
    UserCreateComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule, // <==
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

20.3.2. Impediment: Use the app-create-user tag

Since we did not really do routing yet, we now still have to add a tag to the app.module.html so render the CreateUserComponent when the app runs

Hence, modify your app.component.html to have the app-create-user tag some like this

Example app.component.html (line 8 should be in)
1
2
3
4
5
6
7
8
9
10
11
12
.
.
.

<router-outlet></router-outlet>
<app-users></app-users>

<app-user-create></app-user-create>

.
.
.

20.4. Assignment: Create a CreateUserComponent and consequences

Following the code above now please add a CreateUserComponent and modify your service to follow it’s need

Validation
  • After creating and modifying code, now please run the app

  • Check that you can insert a new user and that an id is printed to the id field in the html

20.5. Assignment: Add some more field to the user model

The user also should have an username and email property.

Implement the username and email property (just like you did with the name) in the CreateUserComponent and Service

21. Enable routing

21.1. Why: Routing

Routing is the way in Angular to map an URL in the form of a string to a component

We route to have a way to navigate between the various components

A routing component is a component which handles the URL(string) to component mapping of the app

How to configure the routing

The most important part of this routing is to know where to find it: app-routing.module.ts The other important part of this routing is to know where to configure it: routes field / array which contains a map of URL to Component mapping(s), with key: path and value: component

The only remaining work to do is when you create your app with routing enabled ($ ng new <appName> --routing) is the step below 8 on the article above
Configurating the routing in app-routing.module.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { UsersComponent } from './users/users.component';
import { UserCreateComponent } from './user-create/user-create.component';

// a json expressing our routes
const routes: Routes = [
  {
                path: 'users',
    component: UsersComponent
  },
  {
    path: 'users/create',
    component: UserCreateComponent
  },
  {
    path: '',
    component: UsersComponent // default route
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {

}

22. UserShowComponent

This module describes how to fetch a user from the DB (using the service which calls the REST api) and displays that user on the view using the UserShowComponent

22.1. Why: UserShowComponent

To have a single responsible component for fetching a detail overview of the user we are interested in

22.2. What: UserShowComponent

The UserShowComponent will be a component which shows all the details (which might be more properties than in the UsersComponent) of the user. It will fetch the data based on the id property of the user

22.3. How: UserShowComponent

22.3.1. Impediment: Service should return user based on id

At first, we have to instruct our service to return a user based on the id

Example of the service
1
2
3
4
5
6
7
...

findById(id: Number): Observable<User> {
    return this.httpClient.get<User>(`${this.url}/${this.endpoint}/${id}`);
}

...
Explaining the code above
  • 3: declare a function findById in the service which expects an id and returns the Observable object with the found user by id

  • 4: return (asynchronous) and calls the REST api with the extension e.g. users/15

22.3.2. Generate the UserShowComponent

Using the Angular CLI generate the new UserShowComponent
$ ng generate component user-show
Valdation
  • The file(s) for the UserShowComponent should be generated in src/app/user-show (user-show.component.ts, .html, .css and .spec.ts)

  • The file app.module.ts should be modified to contain UserShowComponent in the declarations

22.3.3. Modify the routing

Explaining routing with id
After generating the UserShowComponent we are able to route to that component using an expression like this in the app-routing.module.ts
1
2
3
4
5
6
...
{
    path: 'users/:id',
    component: UserShowComponent
}
...
Explaining the code above
  • 3: We want to be able to route to e.g. users/5 which should send an id parameter with the request with a value of 5 to the component

  • 4: please route to UserShowComponent when the application routes to something with /users/:id in it

Using the routing in users.component.html

Since we are adding the routing above you might be interested when we are using that url

This url is used in the users.component.html like this
1
2
3
4
5
6
7
8
  <div>
    Exampe list
    <ul>
      <li *ngFor="let user of users">
        <a [routerLink]="['/users', user.id]">id: {{ user.id }} has name: {{ user.name }} </a>
      </li>
    </ul>
  </div>
Explaining the code above
  • 5: Watch closely; we wrapped the rendering of the id 3 has name: John Doe in a so called HTML a*nchor tag, which links to users, and adds *id to the link

    • so if the id is 3 of the user than a link like this will be generated: <a href="http://localhost:4200/users/3>id 3 has John Doe</a>

22.3.4. Modifying / creating the user-show.component.ts

Now we have to add the view-logic in the UserShowComponent (the .ts file)

Below you find a snippet and (again) I will explain the code below
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';
import { User } from '../user';
import { ActivatedRoute, ParamMap } from '@angular/router';

@Component({
  selector: 'app-user-show',
  templateUrl: './user-show.component.html',
  styleUrls: ['./user-show.component.css']
})
export class UserShowComponent implements OnInit {

  private user: User;

  constructor(
    private userService: UserService,
    private route: ActivatedRoute
  ) {}

 ngOnInit(): void {
          const id = +this.route.snapshot.params["id"];

          this.userService.findById(id).subscribe( user => {
                this.user = user;
          })
        }
}
Explaing the code above
  • 4: import (also) the ParamMap class which is needed to find out the current id in the code later

  • 13: the field user which will be the current user we are interested in

  • 15: constructor with the UserService and the (new for you) ActivatedRoute class which holds the map of the above ParamMap

  • 21: read out the id parameter out of the route map. This code is on it’s on new but it just happens to be this way :-)

    • please watch the smart + sign just before the this.route…​ expressions. It maps the string id to a number id

  • 23: fetch the user by id from the service

22.3.5. Modifying / creating the user-show.component.html

Now we just have to add a component to show the current selected user like this for instance
1
2
3
4
5
6
7
8
9
<h1>Overview of details for user {{ user.name }}</h1>
<div>

  id: {{ user.id }} <br/>
  name: {{ user.name }} <br />
  username: {{ user.username }} <br />
  email: {{ user.email }} <br />

</div>
Explaining the HTML code above
  • X: In fact this snippet just renders using the mustache ({{ …​ }}) operator the user details (id, name, username and email)

22.4. Assignment: Generate UserShowComponent

Using the instruction above now please generate your own UserShowComponent and modify the service

22.5. Assignment: Implement customer change

The customer does not like the fact that the entire line of the user with id is able for clicking. He prefers a Show link on the right side of the row

Please implement this!

23. UserEditComponent

23.1. Why: UserEditComponent

To have a single component to edit the user

23.2. What: UserEditComponent

The UserEditComponent will be responsible for fetching the user by id, updating the content of the user en sending the update request from the component to the service

23.3. How: UserEditComponent

23.3.1. Modify the UserService

First, we (again) have to modify the userService to be able to send out an update / PUT request
1
2
3
4
5
...
update(user: User): Observable<User> {
        return this.httpClient.put<User>(`${this.url}/${this.endpoint}/${user.id}`, user);
}
...
Explaining the code above
  • 2: declare method update which expects a User and returns an Observable with a User in it

  • 3: just invoke the httpClient which updates the user using a PUT request

23.3.2. Modify the routing

Modify the app-routing.module.ts file so that it contains the following
1
2
3
4
5
6
...
{
    path: 'users/edit/:id',
    component: UserEditComponent
}
...
Explaining the code above
  • X: It might be clear now but we just add a route users/edit/:id to that e.g. http://localhost:4200/users/edit/3 renders the UserEditComponent and sends out the id param with value 3

23.3.3. Modify the users.component.html for edit route

Firstly, we have to add the Edit link to the usersComponent like this
1
2
3
...
id: {{ user.id }} has name: {{ user.name }} <a [routerLink]="['/users', user.id]">Show</a>&nbsp;<a [routerLink]="['/users/edit', user.id]">Edit</a>
...
Explaining the HTML code above
  • 2: At the end you see the link to the users/edit/:id which renders the url to the UserEditComponent

23.4. Add the user-edit.component.ts

The user-edit.component looks a lot like the user-show.component.ts with one difference
  • It has an extra update() method to update the user

Content user-edit.component.ts (only diff with user-show)
1
2
3
4
5
6
7
8
...
  update(): void {
    this.userService.update(this.user).subscribe(updatedUser => {
      console.log("Updated in Component: "+updatedUser.id)
    });
  }
}
...
Explaining the code above
  • 2: declare update method with expects nothing (Why?) and returns nothing

  • 3: invoke the userService to update the user which is in the current bound scope (this.user)

  • 4: You might subscribe to it but that is more to print out the changed value or something

Question
  • Should the update not return to the list of users?

    • How we are going to do that is part of the upcoming module(s)

23.4.1. Add the user-edit.component.html

Add the following code to user-edit.component.html
1
2
3
4
5
6
7
8
9
10
11
<h1>Overview of details for user {{ user?.name }}</h1>
<div *ngIf="user">

  id: <input readonly [(ngModel)] = "user.id"><br/>
  name: <input [(ngModel)]= "user.name"> <br />
  username: <input [(ngModel)] = "user.username"><br />
  email: <input [(ngModel)]="user.email"> <br />

  <input type="button" value="Save" (click)="update();">

</div>
Explaining the HTML code above
  • 4: Render an input field using the user.id property which is readonly

  • 5: Render an input field using the user.name property

  • 9: Add a button which invokes the update method in the component when clicked on it

  • X: In fact the input fields are using the ngModel to bind the property to the user field in user-edit.component.ts

24. Remove a User

24.1. Assignment: Remove a user with no warnings (yet)

Now that we did a lot regarding the component and such the customer called in that he is unable to remove a user

Assignment
  • Implement a Delete link right beside the Show link we added which removes a user from the system

Hints
  • See how you implemented the UserShowComponent

  • Is there a user-delete.component.html or is there just a method in the users.component ???

25. Routing and Navigation

Indeed, we already did some routing but this part is the official courseware regarding routing

25.1. Why: Routing and Navigation

Using Routing and Navigation it is possible to redirect from one component to an other component. This is needed since for instance we would have to redirect to the list of users after adding a new user

25.2. What: Routing and Navigation

In Angular routing and navigation is build upon the next parts

Parts of Routing
  • Router

  • Route

  • routerLink directive

  • Location service

  • routerLinkActive directive

25.3. How: Routing and Navigation

There might be some overlap in the following module which we already did during the days/evenings since it was somehow what reactive

25.3.1. Setup routing (automatically)

In fact when we created the application you might already have created the app with the following command

$ ng new <appName> --routing

If you did that the following module is optional

25.3.2. Setup routing (manually)

Add base-href to the head module of the index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>UserApp</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>
Explaining the code above
  • 6: Validate that this line is at the correct location in your index.html

25.3.3. Router imports

The Angular Router is an optional service that presents a particular component view for a given URL, hence it is not part of the Angular core.

It is in its own library package, @angular/router. Import what you need from it as you would from any other Angular package

If you used the --routing option while creating the app, the file AppRoutingModule is created and has the imports instead of the code below
Router imports in app.module.ts
1
2
3
...
import { RouterModule, Routes } from '@angular/router';
...

25.3.4. Configuration

As we already saw, the configuration if the app is done in the file app-routing.module.ts

app-routing.module.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
...
const routes: Routes = [
  {
        path: 'users',
    component: UsersComponent
  },
  {
    path: 'users/create',
    component: UserCreateComponent
  },
  {
    path: '',
    component: UsersComponent // default route
  },
  {
    path: 'users/:id',
    component: UserShowComponent
  },
  {
    path: 'users/edit/:id',
    component: UserEditComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
Explaining the code above
  • X: This file contains the routes const of type Routes which contains an array of Route objects having a path key and component value

    • path: contains a string which is an URL

    • component: contains a Component which the path URL should redirect to

Matching strategy

By default the router will look at what is left in the url, and check if it starts with the specified path (e.g., /team/11/user starts with team/:id).

This is particularly important when redirecting empty-path routes, e.g. ⇒

Error
1
2
3
4
5
6
7
8
[{
  path: '',
  pathMatch: 'prefix', //default
  redirectTo: 'main'
}, {
  path: 'main',
  component: Main
}]
Intermezzo
  • What is wrong here above?

Intermezzo answer
  • every url will always start with a single null character hence the first path mathes everything!!!

Good
1
2
3
4
5
6
7
8
[{
  path: '',
  pathMatch: 'full',
  redirectTo: 'main'
}, {
  path: 'main',
  component: Main
}]
More configuration of Route
  • Besides path and component there are some more attributes

    • pathMatch: 'full' means to match the entire string, else it finds if the beginning of the string matches the url

    • redirectTo: to redirect to (an)other component

      • e.g. path: '' ⇒ redirectTo: '/users'; means that this URL redirects to /users (hence shows the list)

Redirect example
1
2
3
4
5
6
7
8
9
10
11
[{
  path: 'team/:id',
  component: Team,
  children: [{
    path: 'legacy/user/:name',
    redirectTo: 'user/:name'    <=
  }, {
    path: 'user/:name',
    component: User
  }]
}]

25.5. Assignment: Add routing

Target
  • learn how to add a route

Roadmap
  • During this assignment you will learn to add a route from 'users/create' to create a user with the UserCreateComponent

  • You will remove all the tags out of app.component.html BESIDES THE VERY IMPORTANT <router-outlet> tag WHICH REMAINS THERE!!!

  • After creating a user you will redirect to the users list

Steps

The steps for this exercise are below in the next (sub) module ⇒

25.5.1. Modify users.component.html

Modify users.component.html so that it looks like this
1
2
3
4
5
6
7
8
9
10
  <div>
    List of Users
    <ul>
      <li *ngFor="let user of users">
        id: {{ user.id }} has name: {{ user.name }} <a [routerLink]="['/users', user.id]">Show</a>&nbsp;<a [routerLink]="['/users/edit', user.id]">Edit</a>
      </li>
    </ul>

    <button [routerLink]="['/users', 'create']">Create a new user ... </button>
  </div>
Explaining the code above
  • 9: Add a button which links to 'users/create' using Array hence

    • The array method is used to easier express links like: /users/show/3 to ['users', 'show', id] …​

25.5.2. Validate user-create.component.html

Validate that you have the following line in your user-create.component.html
  • <input type="button" (click)="create()" value="Create user">

25.5.3. Modify user-create.component.ts

Modify user-create.component.ts so that it has
  • an injection of the router: Router in the constructor

  • a navigation to users on the last line of the create() method

So the user-create-component has
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
import { Router } from '@angular/router';

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

  private user: User;

  constructor(private userService: UserService, private router: Router) { } // <=

  ngOnInit() {
    this.user = new User();
  }

  create(): void {
   this.userService.create(this.user).subscribe(user => {
      console.log("Created user");
      this.router.navigate(["users"]); // <=
   });
  }
}
Explaining the code above
  • 13: inject the field router of type Router

  • 22: after creating the user, please route to users hence go to the UsersComponent (using the app-routing.component.ts his routes field)

Content app.component.html (similar)
1
2
3
4
5
6
7
8
<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
  <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>

<router-outlet></router-outlet>
Explaining
  • The last line is enough to have the entire routing in, no extra tags should remain here

Validation
  • Start the application

  • There should be a user list

  • Click *Create new user …​"

    • Angular should show a Create user screen

    • Fill in the input fields

    • Click Save

  • Angular routers to the users component

  • The user should now be present in the users view

Follow-up

If you had a user: User field in your users.component.ts you might remove that now since the newly user is now applicable in the UserCreateComponent only

25.6. Assignment: Route from detail to edit

25.6.1. Introduction

Target
  • To learn to route from detail to edit

Roadmap
  • During this assignment you will refactor the views so that the

    • userlist screen only has a Show button to show the details of a user

    • When you Show the details of the user there will appear an Edit button which will redirect to the UserEditComponent, which

      • on it’s turns makes it possible to edit the details of the user

    • After clicking Save on that button the Saved details are show in the UserShowComponent again

Steps
  • in the user-show.component.html add button

    • edit

    • delete

  • in user-show.component.ts add

    • field router: Router

    • delete method

  • in user-service.ts add

    • delete (user:User) method

25.6.2. Validation

Given
  • I have a users view

  • And I have a Show button on that screen

When
  • I click on the Show button

Then
  • I see the details of the user


Given
  • There is an Edit button on the User show view

When
  • I click on the Edit button

Then
  • There is an edit view


Given
  • There is an edit view

When
  • I update some details of the user

  • And I click on the save button

Then
  • The data is saved

  • The user show view is rendered again with the just modified data


Given
  • I am on the users show view

  • And there is a Back button

When
  • I click on the back button

Then
  • The users view is rendered again


Bonus
  • refactor the anchor (a) tags to buttons (button) tags

25.7. (Sub) Topic: routerLinkActive

The routerLinkActive attribute in the a tag
  • is for adding a CSS class to an (anchor <a>) tag when you clicked on the link

  • <a routerLink="…​" routerLinkActive="red" means that if you click the link the CSS class red is applied to the anchor tag

25.8. (Sub) Topic: Location

This topic is related to routing

Using the Location service is considered not the best practice since you are using the browser’s location (affecting the address bar) which might lead to impredictable results

Still I explain it here, since it is here! And relates to Routing

25.8.1. What: Location

Location is a service available in Angular 2+ apps that makes it easy to interact with the current URL path.

25.8.2. Why and When: Location

For most navigation needs, the Angular router is the correct solution, but in a few cases the location service is needed to affect the url without involving the router. Plus, the location service can come-in really handy when coupled with the router to perform certain operations

Try not to use it unless you cannot access the router directly

25.8.3. How: Location

In order to have access to the location service, import it with LocationStrategy and PathLocationStrategy from @angular/common, add the members to your list of providers and inject Location in the constructor:

Code
1
2
3
4
5
6
7
8
9
10
11
...
import { Location, LocationStrategy, PathLocationStrategy } from '@angular/common';

@Component({
...
})
export class AppComponent {
  constructor(private location: Location) { }

  // ...
}
Going back and forward
1
2
3
4
5
6
7
8
// Let’s say that we want methods to go forward or back in the navigation:
goBack() {
  this.location.back();
}

goForward() {
  this.location.forward();
}
Explaining the code above
  • 2: a method in a component which simulates to press the "Back" button on your browser

  • 6: a method in a component which simulates to press the "Forward" button on your browser

Getting the current path
1
2
3
4
// You can get the current path with the Location.path method:
getPath() {
  console.log(this.location.path());
}

25.8.4. Assignment: No

I will leave exercises with the Location Service for yourself or not …​ since it is not the best to do during your projects

routerLink works on both anchor tags and button tags
1
2
<button [routerLink]="['users']">home</button>
<a [routerLink]="['users']">home</a
Using the box/square brackets are mandatory in the button tag whilst optional in the a tag. I just use the box-brackets everywhere I use routerLink but just to remind it!
Finishing routing
  • We covered Route, Router, Location and routerLinkActive during this chapter

In the next module we will learn more regarding Asynchronous Programming and Observable and than we will dive into Angular again …​

26. Asynchronous Programming with JS

Please follow this link Asynchronous Programming

27. Observable

27.1. Introduction

In the previous module - async programming - we learned that there are several ways to code asynchronously using JavaScript. That module was primairly meant to have your mind upto par with working with asynchronous code using callbacks, promises, async await and generators.

When version 2 of Angular came out, it introduced us to observables. Angular uses observables extensively in the event system and the HTTP service. Getting your head around observables can be quite a thing

In Angular there is another way to program asynchronously using Observables. Learning the principles of Observables and (correct) programming with Observables is the subject of this module.

The Observable isn’t an Angular specific feature, but a new standard for managing async data that will be included in the ES7 release.

27.2. What you will learn

In the next module of this tutorial you will learn
  • What Observables are

  • Why to use them

  • When and How to use them

27.3. Why: Observable

The answer to why using Observables lies in simplicicatoin of asynchronous programming starting from EcmaScript 7 using Observables.

Observables are a way of implementing the Publish / Subscribe design pattern which uses an Observable and one ore more Observers

27.4. When: Observable

You can use an Observable everywhere in Angular when you expect an asynchronous stream of data

27.5. What: Observable

Observables are lazy collections of multiple values over time.

Observables provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values.

Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or until they unsubscribe.

An observable can deliver multiple values of any type—literals, messages, or events, depending on the context. The API for receiving values is the same whether the values are delivered synchronously or asynchronously. Because setup and teardown logic are both handled by the observable, your application code only needs to worry about subscribing to consume values, and when done, unsubscribing. Whether the stream was keystrokes, an HTTP response, or an interval timer, the interface for listening to values and stopping listening is the same.

Because of these advantages, observables are used extensively within Angular, and are recommended for app development as well.

27.6. How: Observable

There are in fact two ways of using an Observable which is more based on taste than on tactics …​

27.6.1. Observable using the older way, manuallu subscribing and unsubscribing

This is the most seen way (but not the best and smartest way)

Example user.component.ts using older method but clean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
import { Subscription } from 'rxjs'; // <= watch this new class

@Component({
  selector: 'app-user-show',
  templateUrl: './user-show.component.html',
  styleUrls: ['./user-show.component.css']
})
export class UserShowComponent implements OnInit, OnDestroy {

  private user: User;

  private subscription: Subscription;

  constructor(
    private userService: UserService,
    private route: ActivatedRoute,
    private router: Router
  ) {}

 // @PostConstruct :-) // fetching our task using the id since we are sending it using a GET request
 ngOnInit(): void {
    const id = +this.route.snapshot.params["id"];

    this.subscription = this.userService.findById(id).subscribe( user => {
      this.user = user;
    })
  }

  ngOnDestroy(): void {
   this.subscription.unsubscribe();
  }
}
Explaining the code above
  • 2: import the Subscription class from the rxjs library

    • This is the return type of the subscribe method of the Observable class used in line 13

  • 13: field for storing the subscription result of the subscribe method on line 25

  • 25: here we get the Observable of the userService and subscribe to it, storing the result

  • 31: when the ngOnDestroy lifecycle hook is call(back)ed please unsubscribe from the Observable

Example user-show.component.html (unchanged)
<h1>Overview of details for user {{ user?.name }}</h1>
<div *ngIf="user">

  id: {{ user.id }} <br/>
  name: {{ user.name }} <br />
  username: {{ user.username }} <br />
  email: {{ user.email }} <br />

  <button class="edit" [routerLink]="['/users', 'edit', user.id]">Edit</button>
  <button class="delete" (click)="delete();">Delete</button>

</div>

27.6.2. Observable using async filter

You can use the Observable directly in the component using the following code below which is explained later

The convention to postfix an async / observable variable is a convention in Angular5+
Example users.component.ts (for use with async filter, see below)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
import { Observable } from 'rxjs';

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {

  private users$: Observable<User[]>;

        // dependency injects the userService here as a field / instance var
  constructor(private userService: UserService) {

   }

  ngOnInit() {
     this.users$ = this.userService.list();
  }
}
Explaining the code above
  • 10: Here the users$ is the async result of the call to the server on line 18

  • 18: Fetch the users as users$ from the service and set this async result to the field

Now …​ we can use the fetched async result in the component below ⇒

Example users.component.html (using async filter)
1
2
3
4
5
6
7
8
9
10
  <div>
    Exampe list
    <ul>
      <li *ngFor="let user of users$ | async">
        id: {{ user.id }} has name: {{ user.name }} <button [routerLink]="['/users', user.id]">Show</button>
      </li>
    </ul>

    <button class="create" [routerLink]="['/users', 'create']">Create a new user ... </button>
  </div>
Explaining the code above
  • 4: watch the async keyword after the 'let users of users$' which subscribes and unsubscribes from the Observable users$

27.7. Assignment: Observable ⇒ refactor to use the Subscription class

Target
  • to use the Subscription class of the rxjs library

Roadmap
  • during this exercise you will refactor the users.component (the List component!) to use the Subscription class as shown above

Steps
  • Given the code shown and described above

  • Refactor the users-component to use the subscription class

27.8. Assignment: Observable ⇒ refactor to use the async filter

Target
  • to learn to work using the observable using the async filter

Roadmap
  • during this exercise you will refactor the users.component from the subscribe model to the async filter using model

Steps
  • Given the code shown and described above

  • Refactor the users.component from

    • using the .subscribe and unsubscribe method ( so remove some code )

    • to the async filter ( so add code to the HTML template )

27.9. Conclusion

During this module we learned to work with the details of the Observable class. Although we already worked with it, during this module we learned the details of the Observable class and worked with the Subscription and the async filter

27.10. Further reading

Understanding, creating and subscribing to observables in Angular

https://medium.com/@luukgruijs/understanding-creating-and-subscribing-to-observables-in-angular-426dbf0b04a3

28. Observable ⇒ Pipe

28.1. Introduction

Since Angular 7 we can use the pipe method after having fetched an Observable. It is handy for filtering the returned data of the Observable e.g. to filter out some elements of the Observable which returns all numbers from 1 to 10 and you only are interested in the even numbers. That is a good use case for using the .pipe method.

28.2. What you will learn

In the next module of this tutorial you will learn
  • Why and When you want to use the pipe method of the Observable API

  • What the pipe method does

  • How to use it

28.3. Why and When: Observable ⇒ Pipe

When you have an Observable and want to pass the result through a chain of methods which filter out the data

28.4. What: Observable ⇒ Pipe

This "link" describes very good how the usage of the pipe is

28.5. How: Observable ⇒ Pipe

The How of using a pipe is best demonstrated using an example.

28.5.1. Example 1

Using a Service which returns an Observable of number(s)
1
2
3
 getNumbers(): Observable<number> {
    return of(1, 2, 3, 4, 5, 6, 7);
 }
Component consuming this service::getNumbers and filtering in only even numbers
1
2
3
4
5
6
ngOnInit() {

    this.userService.getNumbers().pipe(filter(n => n % 2 === 0)).subscribe(n => {
      console.log(`Number ${n} is an even number`); // or do something else with this number
    });
  }

28.5.2. Example 2

Using a Service which returns an Observable with a List of Users
1
2
3
list(): Observable<User[]> {
    return this.httpClient.get<User[]>(`${this.url}/${this.endpoint}`);
  }
Component consuming this service::list and filtering in people with name equals to a value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private users$: Observable<User[]>;
private filter = "";

ngOnInit() {
 this.users$ = this.userService.list().pipe(
      retry(3), // if the REST api fails, please do it three times
      map(users =>  // map the users to a users list with only the users which contain the value of the field filter in their name
        users.filter(n => n.name.includes(this.filter))
      ),
      catchError(err => { // and invoke this method when an error occurs
        console.log(err);
        return of([]); // return an empty list ...
      })
    );
}

28.6. Assignment: Observable ⇒ Pipe

Target

To learn working with the Observable and Pipe

Roadmap

During this assignment you will add a Filter to the user app which filters the users based on the username

28.7. Conclusion

During this module we learned how to make use of Observable in general and especially the *pipe(…​) method

28.8. Further reading

Angular Observable pipe

https://www.concretepage.com/angular/angular-observable-pipe

29. Lifecycle Hooks

29.1. Introduction

A component has a lifecycle managed by Angular. Angular creates it, renders it, creates and renders its children, checks it when its data-bound properties change, and destroys it before removing it from the DOM Angular offers lifecycle hooks that provide visibility into these key life moments and the ability to act when they occur.

29.2. What you will learn

In the next module of this tutorial you will learn
  • why we would want to use lifecycle hooks

  • What the most important lifecycle hooks are

  • How to use the lifecycle hooks in your code

29.3. Why and When: Lifecycle Hooks

Directive and component instances have a lifecycle as Angular creates, updates, and destroys them.

Developers can tap into key moments in that lifecycle by implementing one or more of the lifecycle hook interfaces in the Angular core library

It is sometimes useful to invoke code when e.g. a Component start his life or finally dies

29.4. What: Lifecycle Hooks

Each interface has a single hook method whose name is the interface name prefixed with ng. For example, the OnInit interface has a hook method named ngOnInit() that Angular calls shortly after creating the component

29.5. How: Lifecycle Hooks

29.6. Component lifecycle hooks overview

Example (peek-a-boo) component
1
2
3
4
5
6
7
8
9
10
11
12
13
export class PeekABoo implements OnInit { // <=

  constructor(private logger: LoggerService) { }

  // implement OnInit's `ngOnInit` method
  ngOnInit() {
         this.logIt(`OnInit`); // <=
  }

  logIt(msg: string) {
    this.logger.log(`#${nextId++} ${msg}`);
  }
}

No directive or component will implement all of the lifecycle hooks. Angular only calls a directive/component hook method if it is defined.

ngOnChanges()
  • Respond when Angular (re)sets data-bound input properties. The method receives a SimpleChanges object of current and previous property values. Called before ngOnInit() and whenever one or more data-bound input properties change

ngOnInit()
  • Initialize the directive/component after Angular first displays the data-bound properties and sets the directive/component’s input properties. Called once, after the first ngOnChanges()

ngDoCheck()
  • Detect and act upon changes that Angular can’t or won’t detect on its own. Called during every change detection run, immediately after ngOnChanges() and ngOnInit()

ngAfterContentInit()
  • Respond after Angular projects external content into the component’s view / the view that a directive is in. Called once after the first ngDoCheck()

ngAfterContentChecked()
  • Respond after Angular checks the content projected into the directive/component. Called after the ngAfterContentInit() and every subsequent ngDoCheck().

ngAfterViewInit()
  • Respond after Angular initializes the component’s views and child views / the view that a directive is in. Called once after the first ngAfterContentChecked().

ngAfterViewChecked()
  • Respond after Angular checks the component’s views and child views / the view that a directive is in. Called after the ngAfterViewInit and every subsequent ngAfterContentChecked()

ngOnDestroy()
  • Cleanup just before Angular destroys the directive/component. Unsubscribe Observables and detach event handlers to avoid memory leaks. Called just before Angular destroys the directive/component.

29.6.1. Lifecycle sequence

After creating a component/directive by calling its constructor, Angular calls the lifecycle hook methods in the following sequence at specific moments

29.6.2. Interfaces are optional (technically)

The interfaces are optional for JavaScript and Typescript developers from a purely technical perspective. The JavaScript language doesn’t have interfaces. Angular can’t see TypeScript interfaces at runtime because they disappear from the transpiled JavaScript.

Fortunately, they aren’t necessary. You don’t have to add the lifecycle hook interfaces to directives and components to benefit from the hooks themselves.

Angular instead inspects directive and component classes and calls the hook methods if they are defined. Angular finds and calls methods like ngOnInit(), with or without the interfaces.

Nonetheless, it’s good practice to add interfaces to TypeScript directive classes in order to benefit from strong typing and editor tooling.

29.7. Assignment: Lifecycle Hooks

Target
  • To learn working with THE MOST IMPORTANT lifecycle hooks e.g. ngOnInit and ngOnDestroy

Roadmap
  • During this exercise you will learn how to invoke the ngOnInit and ngOnDestroy to VALIDATE that the users.component.ts is ALWAYS having new data when reloaded and mentions that it is reloaded

Steps
  • Given I have this user.show.component.ts .Description

...
export class UserShowComponent /* good practice, unnecessary implements OnInit */ {


  private user: User;

  constructor(
    private userService: UserService,
    private route: ActivatedRoute,
    private router: Router
  ) {}

 ngOnInit(): void {
    const id = +this.route.snapshot.params["id"];

    this.userService.findById(id).subscribe( user => {
      this.user = user;
    })
  }

  delete(): void {
    this.userService.delete(this.user).subscribe(victim => {
        // console.log(`Deleted user ${victim.id}`);
        this.router.navigate(['/users']);
    });
  }
}
  • When

    • This component is unloaded

  • Then

    • I want to have the user field unset

    • And I want to see in the console.log that the user field is unset

    • BONUS: And I want to be sure that it is null or else I want to throw an Error (Hint: create an assert method)

29.8. Solution: Lifecycle Hooks

Possible solution (user.show.component.ts)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
...
export class UserShowComponent implements OnInit, OnDestroy {


  private user: User;

  constructor(
    private userService: UserService,
    private route: ActivatedRoute,
    private router: Router
  ) {}

 ngOnInit(): void {
    const id = +this.route.snapshot.params["id"];

    this.userService.findById(id).subscribe( user => {
      this.user = user;
    })
  }

  delete(): void {
    this.userService.delete(this.user).subscribe(victim => {
        // console.log(`Deleted user ${victim.id}`);
        this.router.navigate(['/users']);
    });
  }

   ngOnDestroy(): void {
    this.user = null;
     console.log(this.user);
   this.assert("user should be null", this.user == null);
  }
}

  assert(message, assertion): void {
    if(!assertion) {
      throw new Error(message);
    }
  }
Explaining the code above
  • 28: add ngOnDestroy lifecycle method which is invoked when the component is destroyed (ends his lifecycle)

  • 31: calls the assert method

  • 35: the assert method

29.9. Conclusion

During this module we learned how to make use of the (sometimes) handy lifecycle methods so that we can inject code during lifecycle hooks of the component

29.10. Further reading

Lifecycle Hooks

https://angular.io/guide/lifecycle-hooks

Be aware that SOME LIFECYCLE HOOKS ( e.g. ngOnChanges ) are only usable and effective when using input and output from and to a Component. We will handle those hooks during the module regarding the input and output to a component which is the subject of the next module

30. Component Interaction

Introduction

In the previous module we learned several lifecycle hooks. In this module we learned there are also some lifecycle hooks which can be used when passing data between parent and child component Working with the communication between parent and child component using the @Input en @Output Angular decorator is the subject of this module

30.1. What you will learn

In the next module of this tutorial you will learn
  • Using the @Input decorator

  • Using the @Output decorator

  • How to work with the @Input and @Output decorator

30.2. @Input

TODOS
  • Setters

  • Explain ngOnChanges

30.2.1. Parent and child explained

At first we have to make clear what a parent component is and what a child component is …​

A parent component

is a component where some other component is nested within

A child component

is a component which is nested in some other component

parent child 1
Figure 1. Example-1

30.2.2. What you will learn

In the next module of this tutorial you will learn
  • Using the @Input decorator

30.2.3. Why and When: @Input

In several reason we have to pass some data (input) from a parent component to a child component. e.g. when we have a UsersComponent and click on a User. Then you might have to show the UserShowComponent which has a nested PostsComponent, which contains the Posts which are written by that user. But …​ the PostComponent should then know for which user he has to show the Posts. Sending something from a component to a child component is done using the @Input decorator which is the subject of this module

30.2.4. What: @Input

parent child 2
Figure 2. Example-2

Image you have a component where you nest in an other component. In our example - and assignment - we want to add the feature to our application so that it is able to show the Posts a User has written.

Than we have to use the @Input decorator

30.2.5. How: @Input

The following code shows the @Input decorator working using code …​

Modify REST service: Add the following to the REST service (watch the posts)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[{
    "id": 1,
    "name": "John Doe",
    "username": "jdoe",
    "email": "john.doe@example.com",
    "posts": [{
      "id": 1,
      "userId": 1,
      "title": "Lorem ipsum dolor sit amet.",
      "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eu magna ac dolor vehicula sollicitudin. "

    },
                {
      "id": 2,
      "userId": 1,
      "title": "I think it rocks",
      "body": "This rocks and it rocks"
    }
                ,
                {
      "id": 3,
      "userId": 1,
      "title": "I love coding Angular",
      "body": "Since I always find what the problem is while coding ... :-)"
    }
        ]
  },
        ...
]
Explaining the JSON file above
  • 6: Add posts to the REST response to have posts per user

Create a Post domain class using Angular CLI
$ ng generate class post (enter)
Modify / add to the Posts domain class
  • Add the following fields to the domain class Post

    • id:Number

    • userId: Number

    • title: string

    • body: string

Example of Post domain class
1
2
3
4
5
6
export class Post {
    id: Number;
    userId: Number;
    title: string;
    body: string;
}
Explaining the code above
  • X: This class represents a Post which is written by a User

  • 3: the userId field is used to represent the user which has written the Post to have the foreign key relationship in order (not perse for this demo)

Create a PostsComponent.ts file
$ ng generate component posts (enter)
Modify the PostsComponent.ts file so that it looks like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Component, OnInit, Input } from '@angular/core';
import { Post } from '../post';

@Component({
  selector: 'app-posts',
  templateUrl: './posts.component.html',
  styleUrls: ['./posts.component.css']
})
export class PostsComponent {

  @Input()
  posts: Post[]; //<===

}
Explaining the code above
  • 11: @Input: says that someone will inject the Posts from outside

  • 12: The Posts

Modify the PostsComponent.html so that it looks like this
<div *ngIf="posts">
  List of Posts
  <ul>
    <li *ngFor="let post of posts">
      <p>
      id: {{ post.id }}
    </p>
    <p>title: {{ post.title }} </p>
    <p>body {{ post.body }}</p>
    </li>
  </ul>
</div>
Explaining the HTML code above
  • X: in fact just a template to show all posts which are in global scope (just like the UsersComponent)

Add the field posts to the user.ts domain class file so that it looks like this
1
2
3
4
5
6
7
8
9
10
11
import { Post } from "./post";

export class User {

        id: number;
        name:string;
        username: string;
        email: string;

        posts: Post[]; // <=
}
Explaining the code above
  • 10: the (added) line for having the posts of the user

And finally, to use the PostsComponent nested in the UserShowComponent add this to the UserShowComponent
1
  <app-posts [posts]="user.posts"></app-posts>
Explaining the HTML code above
  • 1: this (single) line says that on this location there should be a rendered PostsComponent which should have a posts input (!!!) which are the posts of the user (user.posts)

30.2.6. Assignment: @Input

Target

To learn to work with the @Input decorator

Roadmap

During this assignment you will (as the code above) add Posts to the User to show when a user is shown

Steps
  • Given the code above explained

  • Add the POSTS to the JSON rest response

  • Add the modification to your own files

Validation
  • Finally, when the app is run you should be able to click on Show User to show the user AND the posts of that user should be shown

30.2.7. Conclusion

During this module we learned how to make use of the @Input decorator so that we can send data from a component to a nested child component.

But what if the nested child component want to tell something to this parent???

In the following module we will learn that we can make use of the @Output decorator to send something from a child component to a parent component

30.3. @Output

30.3.1. Introduction

In the previous module we learned that we can use @Input to send data from a parent component to a child component

In some cases it is also handy to send data from a child component to a parent component

We can do that using the @Output decorator

Using the @Output decorator is the subject of this module

30.3.2. What you will learn

In the next module of this tutorial you will learn
  • Why you would want to use the @Output decorator

  • When you use it

  • How to use it

30.3.3. Why and When: @Output

You can use the @Output decorator when you want to send data from a child component to a parent component,

For example, when you have a PostsComponent which shows the Posts of a user and want to be able to click a Like button in the PostsComponent which increases the number of likes for that particular User in the UserShowComponent!!!

30.3.4. What: @Output

parent child 2
Figure 3. Example-2

Image you have a component where you nest in an other component. In our example - and assignment - we want to be able to click a Like button which on it’s turn sends data to the parent (usershow) component

Than we have to use the @Output decorator

30.3.5. How: @Output

The following code shows the @Output decorator working using code …​

Modify posts.component.html to have an anchor tag to Like a post
1
2
3
4
5
6
7
8
9
10
11
12
<div *ngIf="posts">
  List of Posts
  <ul>
    <li *ngFor="let post of posts">
      <p>
      id: {{ post.id }} <a href="javascript:void(0);" (click)="vote(1)">Like</a>
    </p>
    <p>title: {{ post.title }} </p>
    <p>body {{ post.body }}</p>
    </li>
  </ul>
</div>
Explaining the code above
  • 6: Here we add a simple anchor tag which onclick invokes the vote method in the PostsComponent

Modify posts.component.ts to have an @Output decorator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Post } from '../post';

@Component({
  selector: 'app-posts',
  templateUrl: './posts.component.html',
  styleUrls: ['./posts.component.css']
})
export class PostsComponent {

  @Input()
  posts: Post[];

  @Output()
  voted = new EventEmitter<number>();

  vote(like: number) {
    this.voted.emit(like);
  }
}
Explaining the code above
  • 1: Add import Output and EventEmitter for later use

  • 14: Add an @Output decorator; which says: hey I am outputting/exporting the votes I receive

  • 15: field voted is the event emitter to send out the newly vote

  • 17: method vote receives a like parameter and emits it (later this will become clear(er))

Modify the user-show.component.html
  • Add likes as variable to count the likes

  • Add PostComponent::(voted) as Output parameter and if updated please invoke UserShowComponent::onVoted(…​)

So that user-show.component.html looks like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<h1>Overview of details for user {{ user?.name }}</h1>
<div *ngIf="user">

  id: {{ user.id }} <br/>
  name: {{ user.name }} <br />
  username: {{ user.username }} <br />
  email: {{ user.email }} <br />
  likes: {{ likes }}

  <app-posts [posts]="user.posts"  (voted)="onVoted($event);"></app-posts>

  <button class="edit" [routerLink]="['/users', 'edit', user.id]">Edit</button>
  <button class="delete" (click)="delete();">Delete</button>


</div>
Explaining the HTML above
  • 8: Add likes using the likes field of the user-show.component.ts

  • 10: Hey Angular, if the voted of the PostComponent is changed THEN I want to be informed of that …​ than please invoke My (the UserShowComponent) onVoted(…​) method please ( in fact the Publish / Subscribe model )

Modify the user-show.component.ts
  • Add likes field

  • Add onVoted(…​) method

So that it looks like this
1
2
3
4
5
6
7
8
9
10
11
12
13
...

private likes  = 0;

...

onVoted(like: number) {
    console.log("voted: "+like);
    like > 0 ? this.likes++ : this.dislikes++;
  }


...
Explaining the code above
  • 3: Add field likes

  • 7: Add method onVoted which is invoked when PostComponent::voted changes!!!

30.3.6. Assignment: @Output

Target

To learn to work with @Output

Roadmap
  • During this exercise you will implement a like button and consequences to the user his PostsComponent which increments the likes of the user

Steps
  • Given the code above as an example please implement it in your own environment

  • When

    • I click the Like button (in the posts.component.html)

  • Then

    • the number of Like(s) in the user-show.component.html is increased

30.3.7. Assignment: Bonus: @Output

Target

To learn to work with @Output more than once

Roadmap
  • During this exercise you will implement a dislike button and consequences to the user his PostsComponent which increments the dislikes of the user (hence add a dislikes field to the User)

Steps
  • Given the code above as an example please implement it in your own environment

  • When

    • I click the Dislike button (in the posts.component.html)

  • Then

    • the number of Dislike(s) in the UserShowComponent is increased

30.3.8. Conclusion

During this module we learned how to make use of the @Output decorator so that we can send out data from a child component (Posts) to a parent component (User) In the following module we will learn that we can (also) make use of some more LifeCycle Event Hooks which are part of the following (sub) topic

30.4. Further reading

Component Interaction

https://angular.io/guide/component-interaction#component-interaction

31. Testing

31.1. Pre introduction

Expectation management :-)
  • During this session we will ONLY focus on what testing is and what good testing is …​

  • And we will learn how to make two tests. Fix a failing test and build a newly one

31.2. Introduction

During this training we constantly worked and worked but made some crucial mistakes …​
  • we did not know that skeletons for test were created

  • we did not make any tests

That time is now over …​ it is time to get acquinted with testing with Angular.

Testing with Angular will be the subject of this module

31.3. What you will learn

In the next module of this tutorial you will learn
  • some introduction regarding good testing

  • what test are

  • how to test

31.4. Why: Testing

Testing shows the presence of errors, not the absence of errors

— E.W. Dijkstra (1930-2002)
Why should we test
  • to show the presence of errors

  • to know that we created pretty good software (how else would we know?)

  • to begin with the end in mind - using Test Driven Development (TDD) we create tests before production-code

31.5. When: Testing

Act or be acted upon

— S. Covey

The above quote means so much as: If you don’t test properly, the rest of the world will do it for you!

Testing can be done
  • during development

    • testing done by developer

  • after development and before acceptance; realisation-testing

    • testing done by tester

  • in production

    • testing done by customer

What the above means? That you do a good testing or the testing is done by your customer! So …​ when should you test? Before the small fish become big sharks! As soon as possible!

31.6. What: Testing

Tests can be divided in several tests
  • Unittests: to test some unit (method) which is considerably small

  • Integrationtests: to test some integration between to classes; the test might be small but the unit of tests is most of the time pretty big and the focus lies on the integration between them

  • end to end tests: just a test from Database / Datastore to View (html)

31.7. How: Testing

Regarding to Angular we can use the following tools for testing

Jasmine

Jasmine is a javascript testing framework that supports a software development practice called Behaviour Driven Development, or BDD for short. It’s a specific flavour of Test Driven Development (TDD). Jasmine, and BDD in general, attempts to describe tests in a human readable format so that non-technical people can understand what is being tested. However even if you are technical reading tests in BDD format makes it a lot easier to understand what’s going on.

For example if we wanted to test this function:
1
2
3
function helloWorld() {
  return 'Hello world!';
}
We could write a test like this
1
2
3
4
5
6
describe('Hello world', () => {
  it('says hello', () => {
    expect(helloWorld())
        .toEqual('Hello world!');
  });
});
Karma

Manually running Jasmine tests by refreshing a browser tab repeatedly in different browsers every-time we edit some code can become tiresome.

Karma is a tool which lets us spawn browsers and run jasmine tests inside of them all from the command line. The results of the tests are also displayed on the command line.

Karma can also watch your development files for changes and re-run the tests automatically.

Karma lets us run jasmine tests as part of a development tool chain which requires tests to be runnable and results inspectable via the command line.

It’s not necessary to know the internals of how Karma works. When using the Angular CLI it handles the configuration for us and for the rest of this module we are going to run the tests using only Jasmine.

Protractor
  • End to End testing tool for Angular

31.8. Structure and files

We will sequentially run through this page of the Angular guide since it seems it up very consisely. So please click here

In the testworld there is a very strong principle we have to explain here ( a little ). Given ⇒ When ⇒ Then

It is even used in Scrumteams to create stories (which are testable!) and it is some like this

Given: I have a calculator

When: I add 2 + 3

Then: The result is 5

Sometimes also called the AAA principle: Arrange, Act, Assert

Angular created testfile (stubs) when creating services, component and classes

The files are located near the generated files itself and are postfixed with *.spec.ts)

In the files you see some code which has the follow structure
  • describe: a describe of some tests which are co-located and should be seen as a whole (testsuite)

  • it: a test itself which is a test (in the body you find the when)

  • expect: an expectation after running the test (then)

We will dive (pretty) deep in this above in the upcoming module

Note to self: Let’s also browse through the slides of the Capgemini pdfs regarding Testing (day 7)

31.9. Conclusion

During this module we learned some background info on Testing so that we now know that we have unittests, integration test and e2e-tests and tools like Jasmine, Karma and Protactor

In the following module we will learn that HOW to make a unittests with Angular

31.10. Further reading and watching

Testing

https://angular.io/guide/testing

Jasmine and Karma

https://codecraft.tv/courses/angular/unit-testing/jasmine-and-karma/

Protractor

http://www.protractortest.org/#/

Youtube movie of Mosh Hamedani regarding Automated Testing

https://www.youtube.com/watch?v=yG4FH60fhUE

32. Unittesting

32.1. Introduction

In the previous module we learned that we have to test our code and we know some background regarding Testing

But we still have to learn to make tests in Angular, starting with unittests

Learning how to make unittest with Angular will be the subject of this module

The fixing of that problem will be the subject of this module

32.2. What you will learn

In the next module of this tutorial you will learn mentally
  • why we have to have a lot of unittests (and even that might be enough for your project, really!)

  • what a good unittests is

  • and of course …​ how to write them

In the next module of this tutorial you will do practically
  • We will run $ ng test and see that it might fail (or not) and we will fix the failings tests on your current user-app project

  • we will add a unittests for the vote component

We might add more regarding testing (integration testing) but that is not part of this evening. For now and this evening …​ unittesting is key!

32.3. Why: Unittesting

testing pyramid

Given the image above which is called the Testing Pyramid we have to have a lot of unittests and than we are pretty confident about our work

32.4. When: Unittesting

Always create unittests …​ even create unitests before writing code is the principle of Test Driven Development (TDD)

32.5. What: Unittesting

A unittests test a relative small part of the application and is always an atomic part
  • method

  • some methods together

    • testing the combination of a setter and a getter

32.6. How: Unittesting

32.6.1. Hickups

When starting the tests using ng test you might see a lot of failures for starters, these might be fixed by following the following tips
  • Add some imports in the beforeEach to have testing of Forms (FormsModule), HttpClient (HttpClientModule) and router (RouterTestingModule) so add this to the import of beforeEach

 imports: [FormsModule, HttpClientModule, RouterTestingModule]
And add this to the beforeEach of the UserService
1
2
3
4
5
6
7
describe('UserService', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [UserService],
      imports: [HttpClientModule] // <= add this!!!
    });
  });
Explaining the most important of the code above
  • 3: TestBed: the bed to test …​ which means so much as of a ground to test on. Where you can configure your tests, add imports and dependencies

On my machine the Chrome driver still keeps failing after running. Although the tests succeed the Chrome browser is uncloseable my ng test. That might be also for you or not :-)

32.6.2. Our first test!!!

Let’s look at a part of the code of the user-show.component

1
2
3
4
5
6
7
8
9
10
11
export class UserShowComponent implements OnInit, OnDestroy {

  ...

  likes  = 0;
  private dislikes = 0;

onVoted(like: number) {
    console.log("voted: "+like);
    like > 0 ? this.likes++ : this.dislikes++;
  }

At first, we can create a very simple test like this (including imports and such for now)

Our first unittest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { UserShowComponent } from './user-show.component';
import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { HttpClientModule } from '@angular/common/http';
import { PostsComponent } from '../posts/posts.component';

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ UserShowComponent, PostsComponent ],
      imports: [FormsModule, RouterTestingModule, HttpClientModule]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(UserShowComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

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

  it('should increment votes when clicked on', () => {
    component.onVoted(1);

    expect(component.likes).toBe(1);
  });

});
Explaining the code above
  • 9: the describe, the start of a testsuite

  • 13: a setup: before each test (it) this will be run

  • 21: a setup: asynchronously: before each test (it) this will be run

  • 27: a test to test of the component is correctly instantiated (more like a given you might say)

  • 31: the test of the vote and voting button

To have this test successfully run I had to add this to the declarations of the beforeEach::TestBed::configuration
1
declarations: [ UserShowComponent, PostsComponent ], // <= had to add PostsComponents since it is used in the user-show.component

32.7. Assignment I: Fix the failing Angular tests

Target

To get and to learn how to get the ng test command succeeding

Roadmap

Using the instruction above and help of the trainer try to get the following command running in your env: ng test (enter)

Really, some adding of the above modules in the imports and | or providers will get it running

32.8. Assignment II: Unittesting a Component

Target

To learn to create your first unittest

Roadmap

Using the example above, for starters, create a unittest for your voting in the app

33. Guards

33.1. Introduction

In the previous module we learned that we can create a user by clicking Create user in the Angular UI. But …​ the customer complained …​ since not everybody should be able to create a new user

So we have now come to a very (im) populair topic Security and especially Guards

Creating and working with Guards will be the subject of this module

Credits: A lot of this module is used from this page regarding Guards on Angular.io so a lot of kudos go to them!!!

33.2. What you will learn

In the next module of this tutorial you will learn
  • Why you would want to use guards

  • When to use them (mostly security related in practise)

  • How to create and implement them!!!

33.3. Why: Guards

Using Guards in necessary when you have an app and should be able to implement security on it. You might wonder …​ we should add security sooner? Or you might wonder …​ we should add security at last? There are several opinons (polymics) and discussions around it! Fact remains that we should be security-aware with EVERY app we make and when to implement it is more customer based.

What we want is an security agnostic application

(Personal note: I like to create my app with all the first needed features in it and them add the security although I am aware that it must be added)

33.4. When: Guards

You use guards when you want to add security and have not much code impact on the existing app! (and it is the best way to add security)

33.5. What: Guards

Guards are guards :-) They are classes which conduct the access of the application / components / routing and are not a part of the application, hence the name Guards

There are several kinds of guards in Angular
  • CanActivate

    • to mediate navigation to a route

    • we will see this one in depth

  • CanDeactivate

    • to mediate navigation away from the current route

    • we will see this one in depth

  • CanActivateChild

    • to mediate navigation to a child route

  • CanLoad

    • to mediate navigation to a feature module loaded asynchronously

  • Resolve

    • to perform route data retrieval before route activation

You can have multiple guards at every level of a routing hierarchy. The router checks the CanDeactivate and CanActivateChild guards first, from the deepest child route to the top. Then it checks the CanActivate guards from the top down to the deepest child route. If the feature module is loaded asynchronously, the CanLoad guard is checked before the module is loaded. If any guard returns false, pending guards that have not completed will be canceled, and the entire navigation is canceled.

In the following parts of this module we will investigate them (especially CanActivate and CanDeactivate since it is used most and the principles are (almost) the same)

33.6. How: Guards

CanActivate: requiring authentication

Applications often restrict access to a feature area based on who the user is.

You could permit access only to authenticated users or to users with a specific role. You might block or limit access until the user’s account is activated.

The CanActivate guard is the tool to manage these navigation business rules.

33.6.1. Generate a guard

Generate a guard to work on and with
syntax: $ ng generate guard <guardName>

e.g.

$ ng generate guard can-enter-this-page
$ ng generate guard can-activate

33.6.2. Implement a Guard

After generating a guard you have some skeleton code like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class CanActivateGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

    // simulate successful login (true) or simulate failing login (false)
    return true;
  }
}

The only (well only???) thing we have to do is implement some code, e.g. call a backend authentication service, use a file to read the username and password from and return true or false in the end

Return values of the Guard
  • true: the user is permitted

  • false: the user is NOT permitted to enter that route ⇒

Add the guard to the routing (app-routing.module.ts)
1
2
3
4
5
{
    path: 'users/create',
    component: UserCreateComponent,
    canActivate: [CanActivateGuard] // <=
  },
Explaining the code above
  • 4: Just add the classname of the guard to the property of canActivate in the routing path and you are on!

33.7. Assignment: Use this guard above

Having the code above using the CanActivateGuard returning only true or false please

implement the guard for the users/create to be open (returning true in the guard) and if that rocks …​ return false and than the url of users/create should not be able to open anymore

Validation
  • when returning false in the guard the users/create should be unable to open!

33.7.1. Use a Guard

Now we have created a poorly guard we will add some code to authenticate using an AuthService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { tap, delay } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor() { }

  isLoggedIn = false;

  // store the URL so we can redirect after logging in
  redirectUrl: string;

  login(): Observable<boolean> {
    return of(true).pipe(
      delay(1000),
      tap(val => this.isLoggedIn = true)
    );
  }

  logout(): void {
    this.isLoggedIn = false;
  }
}
and we will modify the can-activate guard to use that new service (modify canActivate(), add checkLogin() and modify constructor)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export class CanActivateGuard implements CanActivate {

  constructor(private authService: AuthService, private router: Router) {

  }
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

      let url: string = state.url;

      return this.checkLogin(url);
  }

  checkLogin(url: string): boolean {
    if (this.authService.isLoggedIn) { return true; }

    // Store the attempted URL for redirecting
    this.authService.redirectUrl = url;

    // Navigate to the login page with extras
    this.router.navigate(['/login']);
    return false;
  }
}
Explaining the code above
  • This guard returns a synchronous boolean result. If the user is logged in, it returns true and the navigation continues.

  • The ActivatedRouteSnapshot contains the future route that will be activated and the RouterStateSnapshot contains the future RouterState of the application, should you pass through the guard check

  • If the user is not logged in, you store the attempted URL the user came from using the RouterStateSnapshot.url and tell the router to navigate to a login page—a page you haven’t created yet

    • This secondary navigation automatically cancels the current navigation; checkLogin() returns false just to be clear about that

Add the LoginComponent

You need a LoginComponent for the user to log in to the app. After logging in, you’ll redirect to the stored URL if available, or use the default URL. There is nothing new about this component or the way you wire it into the router configuration.

So to generate a LoginComponent
$ ng generate component auth/login (enter)
Modify the login.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../admin/auth.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {

  message: string;

  constructor(private authService: AuthService, private router: Router) {
    this.setMessage();
  }

  setMessage() {
    this.message = 'Logged ' + (this.authService.isLoggedIn ? 'in' : 'out');
  }

  login() {
    this.message = 'Trying to log in ...';

    this.authService.login().subscribe(() => {
      this.setMessage();
      if (this.authService.isLoggedIn) {
        // Get the redirect URL from our auth service
        // If no redirect has been set, use the default
        let redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/crisis-center/admin';

        // Redirect the user
        this.router.navigate([redirect]);
      }
    });
  }

  logout() {
    this.authService.logout();
    this.setMessage();
  }


}
And modify the login.component.html
<h2>Please login</h2>
<p>{{message}}</p>
<p>
  <button (click)="login()"  *ngIf="!authService.isLoggedIn">Login</button>
  <button (click)="logout()" *ngIf="authService.isLoggedIn">Logout</button>
</p>
Register a /login route in the auth/auth-routing.module.ts
1
2
3
4
5
 {
    path: 'login',
    component: LoginComponent

  },
The above mentioned login route should be before the path:"*" routing since else the login route will not be picked up!!!
Congratulations, we / you have now added a pretty good useful use of the CanActivateGuard principle! So time for assignments!

33.8. Assignment I: Implement the CanActivate guard

Target

To learn to work with guards, especially (first) the CanActivateGuard

Roadmap

During this assignment you will implement the CanActivateGuard to the user application including a pretty real simulated authentication

Given
  • the code shown above

  • Please implement the CanActivate Guard to your application

33.9. Assignment II: Add real(er) security to the just created CanActivateGuard

Target

To learn to work with guards and add realer security

Roadmap

During this assignment you will add more security to the CanActivateGuard so that we are having a more real feeling and a realer user realm

Given this modified AutService.ts (with an added realm)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { tap, delay } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor() { }

  // a very, very simple realm
  private realm: { [key: string]: string; } = {

    rloman: "testing2018!",
    george: "testingwithgeorge",
    erika: "erikarocks!" // and more and more names :-)
  }

  isLoggedIn = false;

  // store the URL so we can redirect after logging in
  redirectUrl: string;

  login(username, password): Observable<boolean> {

    let result;

    // first validate for null input
    if (!username || !password) {
      result = false;
    }
    else {
      // validate the user
      if (this.realm[username] === password) {
        result = true;
      }
      else {
        result = false;
      }
    }

    return of(result).pipe(
      delay(1000),
      tap(val => this.isLoggedIn = result)
    );
  }

  logout(): void {
    this.isLoggedIn = false;
  }
}
And this following partly login.component.html
1
2
3
4
5
6
7
8
9
10
<h2>Please login</h2>
<p>{{message}}</p>
<p>

  <input [(ngModel)]='username' />
  <input type="password" [(ngModel)]='password' />

  <button (click)="login()"  *ngIf="!authService.isLoggedIn">Login</button>
  <button (click)="logout()" *ngIf="authService.isLoggedIn">Logout</button>
</p>
Then
  • Finish the login.component.ts file

  • Add your personal username and password to the auth.service.ts

  • You might have other clues regarding the security which are nicer???

33.10. Solution for Assignment II: Add real(er) security to the just created CanActivateGuard

login.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../admin/auth.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {

  message: string;

  private username: string;
  private password: string;

  constructor(private authService: AuthService, private router: Router) {
    this.setMessage();
  }

  setMessage() {
    this.message = 'Logged ' + (this.authService.isLoggedIn ? 'in' : 'out');
  }

  login() {
    this.message = 'Trying to log in ...';

    this.authService.login(this.username, this.password).subscribe(() => {
      this.setMessage();
      if (this.authService.isLoggedIn) {
        // Get the redirect URL from our auth service
        // If no redirect has been set, use the default
        let redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/crisis-center/admin';

        // Redirect the user
        this.router.navigate([redirect]);
      }
    });
  }

  logout() {
    this.authService.logout();
    this.setMessage();
  }
}

34. Can Deactivate Guard

34.1. Introduction

In the previous module we learned that we have a CanDeactivate guard such that we can implement some kind of (pretty simple) security.

Guard can be used for several reasons. Another good reason for using a guard is for moving away from a webpage where you changes something in inputfields. It is quite pityful if a customer moves away from a site forgetting to save

The fixing of that problem will be the subject of this module

34.2. What you will learn

In the next module of this tutorial you will learn
  • The CanDeactivateGuard

  • Why and how to use the CanDeactivateGuard

  • Practising with it

34.3. Why and When: Can Deactivate Guard

You use a CanDeactivate guard for several reaons but a much used use case in the moving away from a website|form use case

34.4. What: Can Deactivate Guard

The CanDeactivate guard is an interface which consists of the following interface
1
CanDeactivate<T>
with the following corresponding method
1
canDeactivate(component: T) {

In this example type T here is a so called generic type

34.5. How: Can Deactivate Guard

In this module we will add the following use case

Given
  • I am in the user-edit component

  • I have changed some data in the edit window

When
  • I try to move away from the user-edit component

Then
  • There should be some kind of alert box to remind me that I did change anything

Given
  • I am in the user-edit component

  • I DID NOT change some data in the edit window

When
  • I try to move away from the user-edit component

Then
  • There should no alert

Given
  • I am in the user-edit component

  • I did or did not change anything in that component

When
  • I click the save button

Then
  • There should no alert

  • The data should be saved

34.5.1. How: To generate a can-deactivate guard

$ ng generate guard can-deactivate
That command generates a a guard like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class CanDeactivateGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}
Yes, you read it well! That command just generated a can-activate guard and that is correct! There is no other way to generate a guard, ⇒
so we must mingle this guard to a can-deactivate guard by amending the code to some like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs';

export interface CanLeaveComponent {
        onLeave() : Observable<boolean> | Promise<boolean> | boolean
}

@Injectable({
  providedIn: 'root'
})
export class CanDeactivateGuard implements CanDeactivate<CanLeaveComponent> {

  canDeactivate(component: CanLeaveComponent) {

    return component.onLeave ? component.onLeave(): true;
  }
}
Explaining the code above
  • 5: Add an interface NEW AND NOT RELATED TO THE CAN-DEACTIVATE GUARD for using in the next lines and other component which need to be shielded from moving away from

  • 6: add an interface method in this case: onLeave() which should return a boolean of Observable or Promise containing a boolean

  • 12: add a class which is the CanDeactivateGuard itself

  • 14: add the method canDeactivate from the CanDeactivate interface which on it’s turn uses the onLeave method from the CanLeaveComponent method

Simply said: this CanDeativateGuard runs the onLeave method on a component when he is about to me moved away from (we will see this in action in the upcoming paragraphs)

Next we will generate and later use a DialogService to prevent moving away which we can use at several places
$ ng generate service dialog
Modify the DialogService so that it contains this (watch the imports)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DialogService {

  constructor() { }

  confirm(message?: string): Observable<boolean> {
    const confirmation = window.confirm(message || 'Is it OK?');

    return of(confirmation);
  };
}
Explaining the code above
  • I would think now the code is pretty self-explaining after this couple of weeks angular???

Next, modify the user-edit.component.ts to have like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
.
.
.

import { CanLeaveComponent } from '../can-deactivate.guard';
import { Observable } from 'rxjs';
import { DialogService } from '../dialog.service';

@Component({
  selector: 'app-user-edit',
  templateUrl: './user-edit.component.html',
  styleUrls: ['./user-edit.component.css']
})
export class UserEditComponent implements OnInit, CanLeaveComponent {

  private user: User;

  private editUser: User; //<= Add this to know that we did or did not change the user!!!

  private saving: boolean = false; // <= to set that we are saving or not!

  constructor(
    private userService: UserService,
    private route: ActivatedRoute,
    private router: Router,
    private dialogService: DialogService // <= inject/wire the DialogService!
  ) { }

  // @PostConstruct :-) // fetching our task using the id since we are sending it using a GET request
  ngOnInit(): void {
    const id = +this.route.snapshot.params["id"];

    this.userService.findById(id).subscribe(user => {

      this.user = user;

      // save the user for later to test if it is changed here! (might be a better way :-)
      this.editUser = new User();
      this.editUser.id = user.id;
      this.editUser.name = user.name;
      this.editUser.username = user.username;
      this.editUser.email = user.email;
    })
  }

  // imlementation of the interface CanLeaveComponent (see above in the class construct)
  onLeave(): boolean | Observable<boolean> | Promise<boolean> {

    if(this.saving) {
      return true;
    }
    else {
        // be aware of order this.user fails since this.user seems not to be a User (typeof is object)
      if(this.editUser.equals(this.user)) {

        console.log("no changes!");
        return true;
      }
      else {
        console.log("Changes detected");

        console.log(this.user);
        console.log(this.editUser);

        return this.dialogService.confirm("Abandon changes?");
      }
    }

  }

  update(): void {

    this.userService.update(this.user).subscribe(updatedUser => {
      console.log("Updated in Component: " + updatedUser.id)
      this.saving = true;
      this.router.navigate(["users", this.user.id]);
    });
  }
}

Now we have a user-edit component which is able to handle the onLeave event but …​ does the router know it?? No, so we finally should inform the router that onLeaving this user-edit component the onLeave method should be invoked, we inform the router like this

Inform the router by modifing app-routing.module.ts
1
2
3
4
5
   path: 'users/edit/:id',
// you can make a button now like this <button [routerLink]="['users', 'edit', user.id]">Edit</button>
    component: UserEditComponent,
    canDeactivate: [CanDeactivateGuard] // <=!!!
  },
Finally (and I made that up myself) add the equals method to the user class
1
2
3
4
5
6
7
8
equals(user: User): boolean {
                if(this.name === user.name && this.email === user.email && this.username === user.username) {
                        return true;
                }
                else {
                        return false;
                }
        }
So the user class looks like this (at least on my machine)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Post } from "./post";

export class User {

        id: number;
        name:string;
        username: string;
        email: string;

        posts: Post[];

        equals(user: User): boolean {
                if(this.name === user.name && this.email === user.email && this.username === user.username) {
                        return true;
                }
                else {
                        return false;
                }
        }
}

After implementing all this code above - which looks more work than it is - we have reached our above mentioned requirements (Given When Then)

34.6. Assignment: Can Deactivate Guard

Target

To learn working with the CanDeactivateGuard

Roadmap

During this assignment you will add and use the CanDeactivate guard principle

Given
  • the code above

Please
  • Implement the CanDeActivate guard for your user-edit component

Verification
  • Please verify that the above mentioned Given / When / Then is reached!!!

34.7. Conclusion

During this module we learned what guards are, why and when to use them and even how to make them and make them working with the Angular app and show the worth them have!

34.8. Follow-up: Can Deactivate Guard

Below you find for this topic some extra resources to watch after the week the topic Can Deactivate Guard is introduced during the training

35. Angular Forms

35.1. Introduction

In the previous modules we implicitly learned and worked with the (older) template driven forms. So we will not dive deep(er) into that since we already know enough of it.

But …​ In this module we will learn how to create fancy forms using the Angular Reactive Forms module which is new since Angular2+

35.2. What you will learn

In the next module of this tutorial you will learn
  • How to setup the Angular Reactive Forms module

  • How to create Angular Reactive Forms

  • Learn working with it using the API

35.3. Why: Angular Forms

We will use Forms when we want to submit some data. So Forms are a very much used HTML principle. So the Why question here is obsolete?

35.4. What: Angular Forms

As described (and read in the following mentioned urls) we have two kind of Angular Forms
  • Template driven (older)

  • Model Driven | Reactive Forms (newer and subject of this module)

The content we will browse through here is found in some external links which I will mention here
We will browse through the link above BUT we will use for this evening and assignment ONLY the part of the document which describes the way using a formGroup in a form, so to send a complete object using the onSubmit. You might have the first part of the document for knowledge later but we will do the latter part of it since that is (my personal opinion) more usable for enterprise apps.
So be aware; although we will browse through the whole link above, we will use formGroups!!!

35.5. When: Angular Forms

Choosing which Angular Forms type
  • You use Angular (Template Driven) Forms when you create a simple app with is not to be exhaustingly tested and uses not a lot of fancy stuff

  • You use Angular (Reactive) Forms when you create an app which is exhaustingly tested and adheres to the more recent techniques

35.6. Optional: Intermezzo: Modify REST and MySQL

Choose to implement the persistence using Array or DB or …​ just leave as is and use console.log to view that you see that your object is correctly when in the onSubmit method So implement your backend quickly or use array quickly or leave open and just use console.log Being able to make a form which is able to be send to the user.service is enough. This is to prevent we will have problems with the backend and do not learn how Angular Reactive Forms work since that is the topic of this evening.

35.6.1. Optional: Intermezzo: Modify the REST service

First
  • amend the REST service to have POST:http://localhost:8081/api/users/3 with RequestBody a post object (userId, title, body)

  • amend the REST service to have GET:http://localhost:8081/api/users/3/posts to fetch all posts for the user (in this code for user with id: 3)

Or
  • Amend your array persistence to add posts to the user

35.6.2. Optional: Intermezzo: Modify the MySQL tables if working with MySQL

Create a table user and post in your database
  • user

    • id: int

    • name: varchar(255)

    • username: varchar(255)

    • email: varchar(255)

  • post

    • id: int

    • userId: int

    • title: varchar(255)

    • body: varchar(255)

35.7. Introducing the assignment

How: Angular Forms assignment flow
  • Story

    • During this module and corresponding assignment we will implement the following use case

      AS a user I WANT to be able to add a post with a title and a body to the system SO THAT someone can read my posts and like them!
Acceptance-criteria
  • Given

    • I am on the user-show.component

  • When

    • I enter a new post for that user there with a title and a body

  • Then

    • The post is saved to the DB or Array and will be visible in the user’s posts later

35.8. How: Angular Forms

Registering the reactive forms module
  • To use reactive forms, import ReactiveFormsModule from the @angular/forms package and add it to your NgModule’s imports array.

Example app.module.ts (partly)
1
2
3
4
5
6
7
  imports: [
    BrowserModule, // this Module also re-exports CommonModule which is imported ngIf, ngFor and the now used  async pipe in UsersComponent.html
    AppRoutingModule,
    FormsModule,
    HttpClientModule,
    ReactiveFormsModule // <=
  ],
Create a create-post component
$ ng generate component CreatePost (enter)
Modify create-post.component.ts so that it looks like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { Component, OnInit, Input } from '@angular/core';
import { FormBuilder, Validators, FormGroup } from '@angular/forms';
import { User } from '../user';
import { UserService } from '../user.service';

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

  constructor(
        private fb: FormBuilder,  // <=
        private userService: UserService) {
  }

  @Input()
  user: User;

  postForm: FormGroup = this.fb.group(
    {
      title: ['', Validators.required], //<= title is default blank and is required!
      body: ['', Validators.required]
    }
  );

  ngOnInit() {
  }

  onSubmit(): void {
    this.userService.addPost(this.user, this.postForm.value).subscribe(newPost => {
      this.user.posts.push(newPost); // <= to reload the posts of this user
    });
  }

}
Explaining the code above
  • 13: In the constructor inject the FormBuilder to build our beloved new form

  • 17-18: Add user as input, since we will be creating a post for this particular user

  • 20: Add the postForm which is a FormGroup which contains the …​

  • 21-23: items we will be filling in for the new post (title and body), which are first blank and both required (Validators.required)

  • 30: This method will be invoked when submitting the form, which on it’s turn calls the userService::addPost

Modify create-post.component.html so that it looks like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<h3>Create a Post for this user ({{ this.user.id}})</h3>

<form [formGroup]="postForm" (ngSubmit)="onSubmit();">

  <label for="title">
    <input type="text" formControlName="title">
  </label>
  <label for="body">
    <input type="text" formControlName="body">
  </label>

  <button type="submit" [disabled]="!postForm.valid">Save</button>

  </form>
Explaining the code above
  • 1: h3 to have a bigger font for title

  • 3: Here we will create the HTML-form corresponding to the postForm in create-post.component.ts and when we click submit we invoke onSubmit

  • 6: the title input text field which is bound to title in the .ts file (formControlName)

  • 8: same for the body

Now we have created and finished and explained the newly create-post.component.ts we can use this component in the user-show.component.ts since we will add the posts there

Modify user-show-component.html to use the newly create-post component
.
.
.
  <app-create-post [user]="this.user"></app-create-post> <!-- // Add this line, and look closely at the input parameter [user] -->

.
.
.
Modify user-show.component.ts to fetch the posts for the user (so change the ngOnInit method)
1
2
3
4
5
6
7
8
9
10
11
12
  ngOnInit(): void {
    const id = +this.route.snapshot.params["id"];

    this.subscription = this.userService.findById(id).subscribe(user => {

      this.userService.findPostsForUser(user).subscribe(posts => { // <=
        this.user = user;
        this.user.posts = posts;
      }
      );
    })
  }
Modify the user.service.ts to have addPosts(…​) and findPostsForUser(…​)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.
.
.

  findPostsForUser(user: User): Observable<Post[]> {
    return this.httpClient.get<Post[]>(`${this.url}/${this.endpoint}/${user.id}/posts`);
  }

  addPost(user: User, post: Post): Observable<Post> {
    post.userId = user.id;
    return this.httpClient.post<Post>(`${this.url}/${this.endpoint}/${user.id}`, post);
  }
.
.
.
Test it
  • Run the app

  • Enter some posts for a user

  • Validate that they are listed when saved

35.8.1. Sidenotes: Managing control values

The tips below might be handy for usage during the assignment and later

Reactive forms give you access to the form control state and value at a point in time. You can manipulate the current state and value through the component class or the component template. The following examples display the value of the form control instance and change it.

Displaying a form control value
You can display the value in these ways:
  • Through the valueChanges observable where you can listen for changes in the form’s value in the template using AsyncPipe or in the component class using the subscribe() method.

  • With the value property. which gives you a snapshot of the current value

    • e.g. this.postForm.value.title to print the title of the newly post

The following example shows you how to display the current value of a newly to be created post title using interpolation in the template.
<p>
  Value: {{ this.postForm.value.title }}
</p>
Replacing a form control value

Reactive forms have methods to change a control’s value programmatically, which gives you the flexibility to update the value without user interaction. A form control instance provides a setValue() method that updates the value of the form control and validates the structure of the value provided against the control’s structure. For example, when retrieving form data from a backend API or service, use the setValue() method to update the control to its new value, replacing the old value entirely.

The following example adds a method to the component class to update the value of the control
<p>
  <button (click)="reset()">Reset</button>
</p>
compontent.ts code
1
2
3
reset() {
  this.postForm.setValue({title: 'Empty title', body: 'Empty body'});
}

35.9. Assignment: Angular Forms

Target

To learn to start working with the Angular Reactive Forms module

Roadmap

During this assignment you will implement a new form to create a Post for a User using the Angular Reactive Forms Manual and the flow we just described above

Steps
  • Following the description above, implement the story to add a post to a user

35.10. Conclusion

During this module we learned how to make use of the Angular Reactive Forms library which concludes the topic of this Angular training.

35.11. Further reading

Angular (1) older Template Driven Forms

https://angular.io/guide/forms

Angular.io (2+) Model Driven / Reactive Forms

https://angular.io/guide/reactive-forms

Overview Key differences of the Angular Form Types

https://angular.io/guide/forms-overview#key-differences

Comparing Angular 2 Forms

https://blog.angular-university.io/introduction-to-angular-2-forms-template-driven-vs-model-driven

Ahead of time compilation

https://blog.angular-university.io/angular2-ngmodule/

36. Configurations

36.1. Introduction

Uptil now we were always working on our own machine (development) and now it is time to deliver our app to the customer. But not before testing it thoroughly using an other collegae which is a real tester and not before the customer is willing to accept the app. Only after the customer accepting the app we will bring the app to production.

In the real world we have kind of four environments we can work in
  1. develop(ment)

  2. test

  3. acceptance

  4. prod(duction)

Working with these environment and especially the location of the files how to work with these environments if the subject of this module

36.2. What you will learn

In the next module of this tutorial you will learn
  • Where the files for setting per environment settings are

  • How to configure them

  • How to use them

In previous Angular version (pre 6) they used the word environment and environments for separate environments as develop, test, acceptance and production. Since Angular 6 that term is renamed to Configuration. Please be aware of that!

36.3. How: Configurations

36.3.1. How: To create a build

Using the following command you create a build
$ ng build --configuration=<configuration>

// this generates a build for the (development) environment since we did not supply an argument after the command
$ ng build
Good reading regarding configurations
They changed the --env to --configuration in Angular6
Example
$ ng serve --configuration=<configuration>

36.3.2. How: Configurations

Configurations in Angular is done using the following files

angular-cli.json
 "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
Example content environment.ts (dev)
export const environment = {
  production: false,
  name: "development",
  tasksUrl:  'http://localhost:8080/api/tasks',
  authUrl: 'http://localhost:8080/auth'
};
Example content environment.prod.ts (prod) for same application
export const environment = {
  production: true,
  name: "",
  tasksUrl:  'http://api.planner.prod.carpago.nl/api/tasks',
  authUrl: 'http://api.planner.prod.carpago.nl/auth'
};
Using the taskUrl
import { Injectable } from '@angular/core';
import { Task } from './task';
import { Dashboard } from './dashboard';
import { Http, Headers } from '@angular/http';
// import { AuthenticationService } from './authentication.service';

import { environment } from '../environments/environment';

import { AuthenticationService } from './authentication.service';


import 'rxjs/add/operator/toPromise';

@Injectable()
export class TaskService {

        // the taskUrl injected / set from the current environment
        private tasksUrl:string = environment.tasksUrl;  // URL to web api


        constructor(
                private http: Http,
                private authenticationService: AuthenticationService
        ) { }

        getTasks(): Observable<Task[]> {

                return this.http.get(this.tasksUrl); //<= using the taskUrl
        }

.
.
.
Using private fields in the component will now fails since they are not accessible when transpiling to JavaScript.
This results in two important tips
  • Always try to deploy as fast as possible in the start phase of a project

  • Try to make a build to another environment (like prod) to have a clue about wheter or not our app is deployable

36.4. Assignment: Configurations

Target

To learn to deploy your app using an other URL to fetch data from

Roadmap

During this assignment you will create an other configuration, set an other url: String in your UserService for fetching data and then make a build for a different environment and deploy that build (for brevity and handy-ness on your own machine)

Given
  • I have the user app

  • Which uses the REST api we created

When
  • I create an acceptance configuration

Then
Assignment
  • Implement this

36.5. Conclusion

In this module we learned how to create an environment (Since Angular6 being called a configuration). In the following module we will learn how to install that build what is called Deployment

Deployment will be the topic of the next module

37. Deployment

37.1. Introduction

In the previous module we learned that we can have multiple environments for deployment

During this -smaller- module we will learn how to deploy the app

37.2. What you will learn

In the next module of this tutorial you will learn
  • How to make a build for deployment

  • How to deploy the build

  • How to test the deploy

37.3. Why and When: Deployment

Obviously, the customer would want to use the application not only on your machine !

37.4. What: Deployment

Deployment in it’s simplest form is copying the created JavaScript files to the target destination

37.5. How: Deployment

Creating a build
$ ng build --configuration=acct  (enter)
Finding the result of the build
  • look in the dist directory

Deploying the build
  • copy the content of dist to a public_www / webroot folder of a server and you are done

37.6. Assignment: Deployment

Target

To learn to create, find and deploy a build

Roadmap

During this assignment you will create a build, find the result of the build and copy the build to a location of your choice. (which might be even just a directory on your filesystem (e.g. C:\Users\johndoe\acceptance\user-app) or something

Steps
  • Go to the user-app root dir

  • issue: ng build --configuration=<some config>

  • cd dist

  • copy . to a webroot of a server like Apache, NGinx or Microft IIS

    • copying it to a local directory seems not to function

  • Using your internet browser open the index.html file in the directory above

During my build I had issues regarding fields which were private and I had to change them to default access (so removed the private which is explainable but unfortunate)

37.7. Conclusion

During this module we learned how to make a build and to deploy the build

In the following module we will recreate an entire app from scratch using the hobby from one of the teammembers: BoardGames

38. Boardgame Case

39. Notes on Service pre Angular5

task.service.ts
1
Was the previous TaskService here see comment in adoc above
REST changed in Angular5
  • Dropped Http in favor of HttpClient

40. Resources