Professional Documents
Culture Documents
Table of Contents
1. Angular CLI
1.1. Scripts
1.1.1. start
1.1.2. build
1.1.3. test
1.1.4. linting
1.1.5. end-to-end testing
1.2. EditorCon몭g
1.3. angular.json
1.4. tscon몭g.json
1.5. Bootstrapping Process
1.6. styles.css
2. Con몭guring WebStorm
2.1. Format Space within braces for ES6 import/export
2.1.1. Option 1: Con몭g in preferences
2.1.2. Option 2: Con몭g in tslint.json
2.2. Turn O몭 IntelliJ Auto Adding to VCS/GIT
2.3. Turn O몭 Warning about Missing Return Type of Function
3. Compiler
3.1. For Debugging
3.2. For Production
3.2.1. Run the app in the dist-folder locally
Python Web Server
Chrome Extension - Web Server for Chrome
4. Angular Ecosystem
4.1. StackBlitz
4.2. Angular Material
4.3. Angular Flex Layout
4.4. Kendo UI for Angular
4.5. Prime NG
4.6. Semantic UI
5. Templates and Data Binding
5. Templates and Data Binding
5.1. Interpolation
5.2. Event-Binding
5.3. Template Expressions
5.4. Property Binding
5.5. Two-Way-Binding
5.6. Structural Directive - *ngFor
5.7. Event with Parameter
5.8. Structural Directive - *ngIf
5.9. Exercise: Turmrechnen
6. Components and Modules
6.1. Components
6.2. Module
6.2.1. Creating a component
6.2.2. Programming a component
6.2.3. Input Parameter
6.2.4. Output Event
6.3. Exercise: Einheitenumrechner
6.3.1. Simple Design of the Application
6.3.2. Set up the Project
6.3.3. Start Coding
6.3.4. Add Communication to the Parent Component
value
unit-of-measure
6.3.5. Exercise
Create a single 몭le component
Extend the unit-converter-example
7. Accessing Web APIs
7.1. Run Demo Server
7.2. Use REST Client in WebStorm
7.3. Consuming Web APIs
7.3.1. Get a List of Persons
7.3.2. Get a List of ToDos
7.3.3. Add a Todo
7.3.4. Add Delete Buttons
7.3.5. Cooking Recipe
7.3.6. Exercise
8. Routing
8.1. What is Routing?
8.2. Implement Routing
8.3. router-outlet
8.3.1. loading the full page
8.3.2. routerLink - partially loading a page
8.3.3. Access the PathParam (the id in the route)
9. RxJS Basics
9.1. Recap
9.2. Introduction
9.3. Method 'of()'
9.4. Method 'interval(…)'
9.5. Unsubscribe with a timer
9.6. Operator 'take(…)'
9.7. Operator 'map(…)'
9.8. Operator '몭lter(…)'
9.9. Function 'concat(…)'
9.10. Function 'merge(…)'
9.11. RxJS for the Angular UI
9.12. RxJS for Web APIs (REST)
10. Flexbox
10.1. 몭ex-direction: row and column
10.2. 몭ex-wrap
10.3. 몭ex-items
10.4. Media Query
10.5. Angular Flex Layout
10.5.1. Installation
10.5.2. Usage
10.5.3. Live Demo
10.5.4. Exercise: conference-agenda
10.5.5. Static API
10.5.6. Grid System
10.5.7. TypeScript API
10.5.8. ngClass-, ngStyle-, …-API
11. Testing with Jasmine
11.1. Testing
11.2. Testing in Angular
11.3. How to write tests
11.3.1. Add a Simple Service
11.3.2. Writing a Function to test
11.3.3. AAA-Pattern
11.3.4. Implement the Test
11.4. To Focus on one Test
11.4.1. How to set a breakpoint in the browser
11.4.2. How to set a breakpoint in Webstorm
11.5. Testing "Edge Cases"
11.6. Mock Objects
11.6.1. Excursus: Inline Reference Information in WebStorm
11.6.2. Create a Spy
11.6.3. Resources for Jasmine
11.7. Disable a Test (Test is Pending)
11.8. Test Modules in Angular
11.8.1. Fixing the example
11.9. Homework
12. OpenID Connect
Credits to Rainer Stropek. This lecture note are based on his Angular Course.
lecture notes
github repo
1. Angular CLI
http://cli.angular.io
Windows
Linux, MacOS
-g → installs global
meta data → data about data meta programming → writing programs that write
programs
The structure of the program 몭les is given. With schematics you can change the way
Angular CLI creates the 몭les.
mkdir angular-intro
cd angular-intro
$ where ng
/usr/local/bin/ng
ng --version
List of Commands
ng
Table 1. Description
Command Description
List of Commands
ng new --help
Table 2. ng new --help
Command Description
--dry-run (-d) Very important. Kind of simulator. Run through and reports
activity without writing out results.
--style SASS → like typescript to javascript, you code in SASS and compile
it down to CSS. SASS supports variables, nestings, etc
ng new my-great-app
no routing
choose CSS
package.json-File
the other dependencies are (open-source) libraries that the Angular team
choosed to use. Parts of theselibraries (like rxjs) are maintained by members of
the Angular core team.
devDependencies
@types/
every project needs some level of manual testing, but we want to reduce
manual testing and increase automated tests
Karma is a framework for running tests (run tests remotely; in the cloud; on 10
di몭erent smartphones)
the versions are responsible for the compability of the libraries to each other.
1.1. Scripts
scripts:
1.1.1. start
Open a terminal in Webstorm and run the app
npm start
http://localhost:4200
1.1.2. build
The result appears in the dist-folder. This is called a debug-buils. It will run on any
web-server. But don’t use it in a production environment at the moment. We will hear
why later on.
1.1.3. test
based on protractor
1.2. EditorCon몭g
https://editorcon몭g.org/
Sets the con몭guration for several IDE’s / editors (VSC, Atom, WebStorm, ….)
1.3. angular.json
Setting 몭le. Don’t touch it at the moment.
1.4. tscon몭g.json
main.ts
1.6. styles.css
Styles can applied globally.
*{
font-family: "Times New Roman", Times, serif;
}
2. Con몭guring WebStorm
2.1. Format Space within braces for ES6 import/export
Instead of import brackets w/o spaces …
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
ij_javascript_spaces_within_imports = true 1
ij_typescript_spaces_within_interpolation_expressions = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
...
"typedef": [
false,
"call-signature"
],
...
3. Compiler
3.1. For Debugging
Angular compiles your html code into javascript. You write Angular templates (which
looks like html)
Normally you have a html page and javascript is used for dynamic behaviour. Angular
works di몭erent. Angular compiles all (html) down to javascript.
the compiler runs just in time → just-in-time-compiler
The 몭le names look pretty strange → a hash of the content of the 몭le is added. For
performance reasons. So the compiler knows which 몭le changed.
When there is a error (ie wrong closed html element) the error is at build time (not
at runtime like before)
Maybe the JIT compiler (for debugging) will be removed in the future
cd dist/my-great-app
python3 -m http.server
https://www.telerik.com/kendo-angular-ui
4.5. Prime NG
https://www.primefaces.org/primeng/
4.6. Semantic UI
https://semantic-ui.com/
<h1>
Welcome to {{ title }}
</h1>
src/app/app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-great-app';
constructor() {
setInterval(() => this.title += '!', 250);
}
}
→ one-way interpolation
5.2. Event-Binding
app.component.ts
@Component({
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-great-app';
constructor() {
}
this.title += '!!';
}
}
app.component.html
<h1>
Welcome to {{ title }}
</h1>
Click me!
</button>
<h1>
Welcome to {{ title }}
</h1>
<button type="button"
(click)="title = title + '!'"> 1
Click me!
</button>
1 There is a danger of getting spaghetti code - mixing ie view and logic → never add
business logic to a view
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-great-app';
myNumber = 41; 1
constructor() {
}
app.component.html
<h1>
Welcome to {{ title }}
</h1>
...
<input type="text" value="asdf" />
Result
...
<input type="text" value="title" />
Result
...
<input type="input" [value]="title" />
Result
5.5. Two-Way-Binding
Combine data binding with event binding
...
<input type="input" [(ngModel)]="title" />
app.module.ts
Check the result in app.module.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-great-app';
myNumber = 41;
todos = [ 1
'Shopping',
'Homework',
'Listen to music'
];
constructor() {
}
<h1>
Welcome to {{ title }}
</h1>
...
<ul>
<li *ngFor="let item of todos">
{{item}}
</li>
</ul>
app.components.html
...
<button type="button" (click)="addItem()">
Add item
</button>
app.components.ts
<ul>
<li *ngFor="let item of todos">
{{item}}
<button type="button"
(click)="removeItem(item)">X
</button>
</li>
</ul>
...
<p *ngIf="alert">
We have a critical alert!!!
</p>
An Angular component represents a visual part of your application. Together you can
use all components to arrange them on the screen.
The Decorator for Components
@Component({ 1
selector: 'app-root', 2
templateUrl: './app.component.html', 3
styleUrls: ['./app.component.css'] 4
})
export class AppComponent {
...
}
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>MyGreatApp</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> 1
</body>
</html>
3 Instead of using a template html 몭le you can also write the html code directly here
app.component.ts
@Component({
selector: 'app-root',
template: '<h2>xxx</h2>', 1
styleUrls: ['./app.component.css']
})
export class AppComponent {
...
}
1 with template you can include html code (for small templates). It is not
recommended to do so.
4 The style only applies to the current component.
app.component.css
h1 {
background: darkorange;
}
6.2. Module
All components are arranged in modules.
In larger projects your modules tend to grow. It is not a practical approach to put all in
a single 몭le.
NgModules consolidate
components,
directives, and
pipes
invoice module
administration module
accounting module
app.module.ts
@NgModule({
declarations: [ 1
AppComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
})
export class AppModule { }
1 This declaration section contains all the components which are part of this module.
app.component.html
<h1>
Welcome to {{ title }}
</h1>
<app-numeric-input></app-numeric-input> 1
app.module.ts
@NgModule({
declarations: [
AppComponent,
NumericInputComponent 1
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
<input type="number"><button>Reset</button>
app.component.html
<h1>
<h1>
Welcome to {{ title }}
</h1>
<app-numeric-input></app-numeric-input>
app.component.html
<h1>
Welcome to {{ title }}
</h1>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
6.2.3. Input Parameter
Communication between child- and parent-component
numeric-input.component.ts
import {Component, Input, OnInit} from '@angular/core'; 1
@Component({
selector: 'app-numeric-input',
templateUrl: './numeric-input.component.html',
styleUrls: ['./numeric-input.component.css']
})
export class NumericInputComponent implements OnInit {
constructor() { }
ngOnInit(): void { 3
}
}
app.component.html
<h1>
Welcome to {{ title }}
</h1>
<app-numeric-input [value]="42"></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
numeric-input.component.html
not so easy
@Component({
selector: 'app-numeric-input',
templateUrl: './numeric-input.component.html',
styleUrls: ['./numeric-input.component.css']
})
export class NumericInputComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
public onResetClicked() { 3
this.resetClicked.emit();
}
1 a
2 b
3 we delegate it to the parent. The child informs the parent, that the click event
happened.
app.component.ts
...
onReset() {
console.log('Reset clicked!');
}
...
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-great-app';
myFirstValue = 42; 1
constructor() {
}
onReset() {
this.myFirstValue = 0; 2
}
}
app.component.html
<h1>
Welcome to {{ title }}
</h1>
<app-numeric-input
[value]="myFirstValue" 1
(resetClicked)="onReset()">
</app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<app-numeric-input></app-numeric-input><br/>
<table>
<td><app-unit-ps-kw
[value]="30"
[unit]="'PS'"
>
ng new unit-converter
@NgModule({
declarations: [
AppComponent,
AppComponent,
InputPsKwComponent 2
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
https://de.wikipedia.org/wiki/VW_K%C3%A4fer
https://de.wikipedia.org/wiki/Ferrari_LaFerrari
app.component.html
<table>
<thead>
<tr>
<td>Car Model</td>
<td>Power</td>
</tr>
</thead>
<tbody>
<tr>
<td>VW Käfer 1936</td>
<td>
22PS
<app-input-ps-kw></app-input-ps-kw> 1
</td>
</tr>
</tbody>
</table>
input-ps-kw.component.html
<select>
<option>PS</option>
<option>KW</option>
</select>
input-ps-kw.component.html
input-ps-kw.component.ts
...
export class InputPsKwComponent implements OnInit {
value = 30;
uom = "PS"; // unit of measures
...
value
1. Add the @Input-Decorator to the 몭eld (value).
input-ps-kw.component.ts
@Component({
selector: 'app-input-ps-kw',
templateUrl: './input-ps-kw.component.html',
styleUrls: ['./input-ps-kw.component.css']
})
export class InputPsKwComponent implements OnInit {
@Input() value = 30; 2
uom = "KW"; // unit of measures
constructor() { }
ngOnInit(): void {
}
app.component.html
<table>
<thead>
<tr>
<td>Car Model</td>
<td>Power</td>
</tr>
</thead>
<tbody>
<tr>
<td>VW Käfer 1936</td>
<td>
22PS
<app-input-ps-kw value="22"></app-input-ps-kw> 1
</td>
</tr>
<tr>
<td>Ferrari LaFerrari</td>
<td>
588KW
<app-input-ps-kw value="588"></app-input-ps-kw> 2
</td>
</tr>
</tbody>
</table>
unit-of-measure
...
export class InputPsKwComponent implements OnInit {
@Input() value = 30;
@Input() uom = "KW"; // unit of measures 1
constructor() { }
ngOnInit(): void {
}
...
...
<tr>
<td>VW Käfer 1936</td>
<td>
<app-input-ps-kw value="22" [uom]="'PS'"></app-input-ps-kw> 1
</td>
</tr>
<tr>
<td>Ferrari LaFerrari</td>
<td>
<app-input-ps-kw value="588" uom="KW"></app-input-ps-kw> 2
</td>
</tr>
...
1 because here the square brackets are used (one-way-data-binding), "PS" must
surrounded additionally be single quotes. Otherwise PS would be interpreted as
variable name.
2 without the square brackets, "KW" is 몭ne w/o single quotes
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
kaeferPower = 22; 1
kaeferUom = 'PS'; 2
}
app.component.html
...
<tr>
<td>VW Käfer 1936</td>
<td>
<app-input-ps-kw
[value]="kaeferPower" 1
[uom]="kaeferUom" 2
></app-input-ps-kw>
</td>
</tr>
<tr>
<td>Ferrari LaFerrari</td>
<td>
<app-input-ps-kw value="588" uom="KW"></app-input-ps-kw>
</td>
</tr>
</tbody>
</tbody>
</table>
...
export class InputPsKwComponent implements OnInit {
@Input() value = 30;
@Output() valueChange = new EventEmitter();
The name of the output is the same as the name of the input + the su몭x
'Change' → naming convention
input-ps-kw.component.html
input-ps-kw.component.js
...
onPowerChanged() {
this.valueChange.emit();
}
onUomChanged() {
this.uomChange.emit();
}
}
app.component.html
...
<tr>
<td>VW Käfer 1936</td>
<td>
<app-input-ps-kw
[(value)]="kaeferPower"
[(uom)]="kaeferUom"
></app-input-ps-kw>
</td>
</tr>
...
...
input-ps-kw.component.js
...
export class InputPsKwComponent implements OnInit {
@Input() value = 30;
@Output() valueChange = new EventEmitter<number>(); 1
constructor() { }
ngOnInit(): void {
}
onPowerChanged() {
this.valueChange.emit(this.value); 3
onUomChanged() {
this.uomChange.emit(this.uom); 4
}
}
6.3.5. Exercise
terminal output
--flat
When true, creates the new files at the top level of the current project.
...
--inline-style (-s)
When true, includes styles inline in the component.ts file. Only CSS styles can
be included inline. By default, an external styles file is created and referenced in
the component.ts file.
--inline-template (-t)
When true, includes template inline in the component.ts file. By default, an
external template file is created and referenced in the component.ts file.
external template file is created and referenced in the component.ts file.
long version
short version
ng g c hello -s -t --flat -d
terminal output
ng g c hello -s -t --flat
rm ./src/app/hello.component.spec.ts
@Component({
selector: 'hello',
template: `<h1>Hello {{name}}!</h1>`,
styles: [
]
})
export class HelloComponent implements OnInit {
export class HelloComponent implements OnInit {
@Input() name: string;
constructor() { }
ngOnInit(): void {
}
see also:
Use Single File Components by Default in Angular
make the table-header background lightgrey with a solit black border at the
bottom
input-ps-kw.component.ts
input-ps-kw.component.html
input-ps-kw.component.css
app.component.ts
app.component.html
app.component.css
Solution on StackBlitz
download
curl -L https://github.com/htl-leonding-example/demo-
api/releases/download/1.0.0/demo-api.jar -o demo-api.jar
run
check, if it works
http://localhost:8080/q/swagger-ui/
Use nodejs
requests.http
###
// Get a list of todo items
GET {{host}}/todos
###
// Add a todo item
POST {{host}}/todos
Content-Type: application/json
{
"description": "Shopping",
"assignedTo": "Eve"
}
###
// Add a todo item with unknown person
POST {{host}}/todos
Content-Type: application/json
{
"description": "Shopping",
"assignedTo": "Nobody"
}
###
// Get first todo item
GET {{host}}/todos/0
###
// Update todo item
PATCH {{host}}/todos/0
Content-Type: application/json
{
"description": "Homework"
}
###
// Update todo item to unknown person
PATCH {{host}}/todos/0
Content-Type: application/json
{
"assignedTo": "Nobody"
"assignedTo": "Nobody"
}
###
GET {{host}}/todos
###
// Update todo item
PATCH {{host}}/todos/0
Content-Type: application/json
{
"done": true
}
###
GET {{host}}/todos
###
// Delete todo item
DELETE {{host}}/todos/0
###
GET {{host}}/todos
@Component({ ...
})
export class MyComponent {
HttpClient is a service
ng new todo-rest
cd todo-rest
webstorm .
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule, HttpClientModule 1
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
1 add HttpClientModule
2 the import will be done automatically
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'todo-rest';
}
}
app.component.ts
interface IPerson {
name: string;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
people: IPerson[] = []; 1
async loadPeople() { 2
this.people = await this.http
.get<IPerson[]>('http://localhost:8080/api/people')
.toPromise();
}
}
app.component.html
<ul>
<li *ngFor="let person of people">{{person.name}}</li>
</ul>
<ul>
<li *ngFor="let person of people">{{person.name}}</li>
</ul>
<ul>
<ul>
<li *ngFor="let todo of todos">{{todo.description}}</li>
</ul>
app.component.ts
interface IPerson {
name: string;
}
interface ITodoItem {
id: number;
description: string;
assignedTo: string;
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
people: IPerson[] = [];
todos: ITodoItem[] = [];
async loadPeople() {
this.people = await this.http
.get<IPerson[]>('http://localhost:8080/api/people')
.toPromise();
}
async loadTodos() {
this.todos = await this.http
.get<ITodoItem[]>('http://localhost:8080/api/todos')
.toPromise();
}
}
<ul>
<li *ngFor="let person of people">{{person.name}}</li>
</ul>
</ul>
<ul>
<li *ngFor="let todo of todos">{{todo.description}}</li>
</ul>
app.component.ts
...
async addDemoData() {
await this.http
.post('http://localhost:8080/api/todos', {
'description': 'Shopping',
'assignedTo': 'Eve'
}).toPromise();
this.loadTodos();
}
...
<ul>
<li *ngFor="let person of people">{{person.name}}</li>
</ul>
<ul>
<li *ngFor="let todo of todos">
{{todo.description}} <button (click)="deleteItem(todo.id)">X</button>
</li>
</ul>
app.component.ts
...
async deleteItem(id: number) {
await this.http.delete(`http://localhost:8080/api/todos/${id}`).toPromise();
this.loadTodos();
}
...
Parameter: ${id}
use backticks, because of parameters
await
.toPromise()
In real world nobody uses http directly. You create your own service.
7.3.6. Exercise
https://github.com/htl-leonding-college/htl-mobile-
computing/tree/master/angular/9020-ng-todo
8. Routing
8.1. What is Routing?
A router is a component that takes the url of a page and turns it into html. Navigation
in the app
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule 2
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
exports: [RouterModule] 4
})
export class AppRoutingModule { }
];
8.3. router-outlet
app-component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'router-demo';
}
customers.component.html
<ul>
<li *ngFor="let c of customers">{{ c.name }}</li>
</ul>
8.3.2. routerLink - partially loading a page
<ul>
<li *ngFor="let c of customers">
<a href="/customers/{{ c.id }}">{{ c.name }}</a>
</li>
</ul>
Problem:
Every time when loading a detail page and when returning to the overview page,
the whole pages are loaded.
1 <ul>
2 <li *ngFor="let c of customers">
3 <a [routerLink]="c.id">{{ c.name }}</a>
4 </li>
5 </ul>
In our simple app this is not necessary, the id wil not change all the time. We will
simplify the work with the paramMap and work w/o observables.
customers-detail.components.ts
public id = '';
We subscribe to the paramMap and get the id once at the beginnening, when the
customer is loaded.
customers.component.html
9. RxJS Basics
9.1. Recap
For better understanding please view this …
Promises
9.2. Introduction
Reactive extensions for Javascript
Observable: object where an outsider (observer) can look at and the observer is
noti몭ed when something interesting happens
When clicking the button an event is sent to the observer (our typescript project)
Another observable is an web api call. If we call a web api the browser is doing the
network tra몭c in an asynchronous way. So you are just initiating the network call,
but then you have to wait until the browser actively noti몭es you: "I am done"
This is the reason why the network call (http client GET, POST, …) is an observable.
You will be noti몭ed once the network request has been completed
The observable is NOT be active until somebody asks me, wether something is
happening. This would be polling.
The observable activiely pushes data to the observer when something happens.
The observer (as the consumer) only registrates a function and the observable will
call this function.
app.component.ts
@Component({
selector: 'app-root',
template: `
<button (click)="doSomethingWithRx()">Start</button>
`,
styles: []
})
export class AppComponent {
doSomethingWithRx() {
console.log("Let's start ...");
const observable = new Observable()
const observable = new Observable()
}
}
http://reactivex.io/
https://rxjs-dev.몭rebaseapp.com/
https://angular.io/guide/rx-library
https://www.learnrxjs.io/
This is the method which will be called as soon as the observer starts to listen.
The observer provides a method which will be called when something happens.
app.component.ts
app.component.ts
...
const observable = new Observable(subscriber => {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
...
With .next(…) the observable can send data to the subscriber (observer).
app.component.ts
...
doSomethingWithRx() {
console.log("Let's start ...");
const observable = new Observable(subscriber => {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
subscriber.complete();
});
observable.subscribe( 1
1 doSomethingWithRx() {
2 console.log('Let\'s start ...');
3 const observable = new Observable(subscriber => {
4 subscriber.next(1);
5 subscriber.next(2);
6 subscriber.next(3);
7 setTimeout(() => { 1
8 subscriber.next(4);
9 subscriber.next(5);
10 subscriber.complete();
11 }, 250);
12 });
13
14 observable.subscribe(
15 val => console.log(`I got ${val}`)
16 );
17 }
1 here we simulate the execution of asynchronous code
1 doSomethingWithRx() {
2 console.log('Let\'s start ...');
3 const observable = new Observable(subscriber => {
4 subscriber.next(1);
5 subscriber.next(2);
6 subscriber.next(3);
7 setTimeout(() => {
8 subscriber.next(4);
9 subscriber.error('Something bad happened ...');
10 subscriber.next(5);
11 subscriber.complete();
12 }, 250);
13 });
14
15 observable.subscribe(
16 val => console.log(`I got ${val}`),
17 err => console.log(`Ops: ${err}`)
18 );
19 }
https://rxjs-dev.몭rebaseapp.com/api/index/function/of
// observable.subscribe(
// val => console.log(`I got ${val}`),
// err => console.log(`Ops: ${err}`)
// );
of(1, 2, 3, 4, 5, 6).subscribe(
val => console.log(`I got ${val}`)
);
https://rxjs-dev.몭rebaseapp.com/api/index/function/interval
interval(250).subscribe(
val => console.log(`I got ${val}`)
);
Observer
Observable
Subscription
concat(
interval(250)
.pipe(take(5)),
.pipe(take(5)),
interval(100)
.pipe(take(5))
).pipe(map(x => x * 2))
.subscribe(val => console.log(`I got ${val}`));
merge(
interval(250)
.pipe(take(5)),
interval(100)
.pipe(take(5))
).pipe(map(x => x * 2))
.subscribe(val => console.log(`I got ${val}`));
RxJS is very powerful. But what does this mean for Angular?
1 Because we removed the .subscribe(…) this Observable is cold and will not work.
@Component({
selector: 'app-root',
template: `
<button (click)="doSomethingWithRx()">Start</button>
<p>{{ values | async }}</p> 1
`,
styles: []
})
1 when we add "| async" the ui subscribes to the observable and it works
9.12. RxJS for Web APIs (REST)
cd ./htl-mobile-computing/angular/0010-demo-api
npm start
app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule 2
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
@Component({
selector: 'app-root',
template: `
<button (click)="doSomethingWithRx()">Start</button>
<ul>
<li *ngFor="let v of values | async">{{v.name}}</li> 1
</ul>
`,
styles: []
})
export class AppComponent {
doSomethingWithRx() {
this.values = this.http.get<any[]>("http://localhost:8080/api/people")
.pipe(retry()); 2
}
}
10. Flexbox
responsive apps
https://caniuse.com/#feat=몭exbox
https://developer.mozilla.org/en-
US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox
Semantic-ui is based on 몭exbox: https://semantic-ui.com/examples/grid.html
.box {
display: flex;
}
10.2. 몭ex-wrap
10.3. 몭ex-items
Google-Suche: css 몭exbox
10.5.1. Installation
install @angular/몭ex-layout, @angular/cdk
import FlexLayoutModule
https://github.com/angular/몭ex-layout#getting-started
10.5.2. Usage
instead of css-몭les you can use Angular-directives
mediaQuery de몭nitions
https://github.com/angular/몭ex-layout/wiki/API-Documentation
https://github.com/angular/몭ex-layout/wiki/Responsive-API
https://github.com/angular/몭ex-layout/wiki/Responsive-API#mediaqueries-and-
aliases
https://github.com/angular/몭ex-layout/wiki/ngClass-API
Sometimes, when 몭xing an error (ie login) another error occurs (ie in registration
page).
The error on the registration page exists, because of 몭xing the login.
This is called a regression bug. Fixing or extending your code may have side-
e몭ects to existing parts of code.
Therefore you have to use regresseion testing: Testing the existing code again and
again.
With automated tests you are preventing bugs not only 몭xing bugs.
npm test
When changing something, and clicking into the terminal window, the tests run
again automatically.
The test 몭le for our simple test is unnecessarily too complex
describe('CircleMathService', () => {
let service: CircleMathService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(CircleMathService);
});
describe('CircleMathService', () => { 1
it
2 it should be created
11.3.3. AAA-Pattern
describe('CircleMathService', () => {
it('should calculate the circles area correctly', () => {
// Prepare (arrange, given)
Write nearly passing tests at the beginning. Don’t write passing tests.
Every test should fail once. (ie const result =
mathService.calculatorCircleArea(1.1);)
You can start/test/debug the app in the terminal but also in Webstorm
itself.
graphic-math.service.ts
Create a test
graphic-math.service.spec.ts
describe('GraphicMathService', () => {
it('should calculate areas of circles correctly', () => {
// arrange
const graphicMathService = new GraphicMathService(new CircleMathService());
graphicMathService.circleRadiuses.push(1);
graphicMathService.circleRadiuses.push(2);
// act
graphicMathService.calculateAreasOfAllCircles();
// assert
expect(graphicMathService.circleAreas.length).toBe(2);
expect(graphicMathService.circleAreas[0]).toBe(Math.PI);
expect(graphicMathService.circleAreas[1]).toBe(2 * 2 * Math.PI); 1
});
});
1 2 * 2 * Math.PI → This is not good. Don’t repeat the business logic. When the
algorithm for calculting the area would change, all tests must be rewritten
// act
graphicMathService.calculateAreasOfAllCircles();
// assert
expect(graphicMathService.circleAreas.length).toBe(0);
});
In a ideal project the end users will give you the test cases to implement
The customers tells you: "If I input this, I will get that" → write SysSpec and or User
Stories
We need mock objects to test only one aspect that means only one class.
in VSC: peek-in-de몭nition
});
On the left hand, you see the theory, on the right hand the code
11.7. Disable a Test (Test is Pending)
use xit instead of it
app.component.html
<h1>Calculator</h1>
app.component.html
<h1>Calculator</h1>
<p>
<label>Radius:</label>
<input type="number" [(ngModel)]="radius"><br/>
<button (click)="calculate()">Calculate</button>
</p>
<p>
The result is <span>{{ result }}</span>
</p>
Because of Mockups
app.component.spec.ts
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents(); 1
}));
1 this module is for testing only with mockups. It does not run dependencies.
<h1>Calculator</h1>
<p>
<label>Radius:</label>
<input type="number" [(ngModel)]="radius"><br/>
<button (click)="calculate()">Calculate</button>
</p>
<p>
The result is <span>{{ result }}</span>
</p>
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'jasmine-intro';
radius = 1;
result: number;
calculate() {
this.result = this.calculator.calculateCircleArea(this.radius);
}
}
11.9. Homework
https://github.com/htl-leonding-college/htl-mobile-
computing/tree/master/angular/0080-testing
Now the user data is centralized, the apps / services are accessing this central store
hires at a competitor
now a competitor can access this service ie discussion group for important stu몭
resource owner
id-token → passport
access-token → visa
Version 1.0.0
Last updated 2021-04-28 09:53:44 UTC