Slide 1

Slide 1 text

Detecting & solving pain points in applications

Slide 2

Slide 2 text

PErsonal Experience

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Feature Modules

Slide 5

Slide 5 text

Feature Modules Libraries

Slide 6

Slide 6 text

Feature Modules Libraries Monorepos

Slide 7

Slide 7 text

Feature Modules Libraries Monorepos Component Relation

Slide 8

Slide 8 text

Feature Modules Libraries Monorepos Component Relation Component Communication

Slide 9

Slide 9 text

Feature Modules Libraries Monorepos Component Relation Component Communication Rxjs

Slide 10

Slide 10 text

Detecting & solving pain points in applications

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

What is

Slide 13

Slide 13 text

Platform

Slide 14

Slide 14 text

Animations CDK CLI Compiler Components Dependency Injection Forms Http

Slide 15

Slide 15 text

L18n Karma Libraries Material Protractor PWA Router Universal

Slide 16

Slide 16 text

NgRx Cypress RxJs Language Service Lazy Loading

Slide 17

Slide 17 text

Platform !

Slide 18

Slide 18 text

THe Start

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { HelloComponent } from './hello.component'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent, HelloComponent ], bootstrap: [AppComponent] }) export class AppModule { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Slide 21

Slide 21 text

import { NgModule } from '@angular/core'; @NgModule({ imports: [ ... ], declarations: [ AppComponent, HelloComponent, Hello1Component, Hello2Component, Hello3Component, Hello4Component, Hello5Component, Hello6Component, Hello7Component, Hello8Component, Hello9Component, Hello10Component, Hello11Component, Hello12Component, Hello13Component, Hello14Component, Hello15Component 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

Slide 22

Slide 22 text

Feature Modules

Slide 23

Slide 23 text

import { NgModule } from '@angular/core'; @NgModule({ imports: [ ... ], declarations: [ AppComponent, HelloComponent, Hello1Component, Hello2Component, Hello3Component, Hello4Component, Hello5Component, Hello6Component, Hello7Component, Hello8Component, Hello9Component, Hello10Component, Hello11Component, Hello12Component, Hello13Component, Hello14Component, Hello15Component 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

Slide 24

Slide 24 text

import { NgModule } from '@angular/core'; @NgModule({ imports: [ ... ], declarations: [ AppComponent, Feature1Component1, Feature1Component2, Feature1Component3, Feature1Component4, Feature1Component5, Feature1Component6, Feature2Component1, Feature2Component2, Feature2Component3, Feature2Component4, Feature2Component5, Feature2Component6, ... ], bootstrap: [AppComponent] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

Slide 25

Slide 25 text

import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [ Feature1Component1, Feature1Component2, Feature1Component3, Feature1Component4, Feature1Component5, Feature1Component6, ] }) export class Feature1Module { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Slide 26

Slide 26 text

import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [ Feature2Component1, Feature2Component2, Feature2Component3, Feature2Component4, Feature2Component5, Feature2Component6, ] }) export class Feature2Module { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Slide 27

Slide 27 text

import { NgModule } from '@angular/core'; @NgModule({ imports: [ ], declarations: [ AppComponent, Feature1Component1, Feature1Component2, Feature1Component3, Feature1Component4, Feature1Component5, Feature1Component6, Feature2Component1, Feature2Component2, Feature2Component3, Feature2Component4, Feature2Component5, Feature2Component6, ], }) export class AppModule { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

Slide 28

Slide 28 text

import { NgModule } from '@angular/core'; import { Feature1Module } from './feature1-module/feature1.module'; import { Feature2Module } from './feature2-module/feature2.module'; @NgModule({ imports: [ BrowserModule, FormsModule, Feature1Module, Feature2Module ], declarations: [ AppComponent, HelloComponent ], bootstrap: [ AppComponent ] }) export class AppModule { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Slide 29

Slide 29 text

import { NgModule } from '@angular/core'; import { Feature1Module } from './feature1-module/feature1.module'; import { Feature2Module } from './feature2-module/feature2.module'; @NgModule({ imports: [ BrowserModule, FormsModule, Feature1Module, Feature2Module ], declarations: [ AppComponent, HelloComponent ], bootstrap: [ AppComponent ] }) export class AppModule { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { Feature1Module } from './feature1-module/feature1.module'; import { Feature2Module } from './feature2-module/feature2.module'; Feature1Module, Feature2Module import { NgModule } from '@angular/core'; 1 2 3 4 @NgModule({ 5 imports: [ 6 BrowserModule, 7 FormsModule, 8 9 10 ], 11 declarations: [ 12 AppComponent, 13 HelloComponent 14 ], 15 bootstrap: [ AppComponent ] 16 }) 17 export class AppModule { } 18

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [ Feature2Component1, Feature2Component2, Feature2Component3, Feature2Component4, Feature2Component5, Feature2Component6, ] }) export class Feature2Module { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Slide 32

Slide 32 text

import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [ Feature2Component1, Feature2Component2, Feature2Component3, Feature2Component4, Feature2Component5, Feature2Component6, ], exports: [ Feature2Component5, Feature2Component6, ] }) export class Feature2Module { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

Slide 33

Slide 33 text

import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [ Feature2Component1, // private Feature2Component2, // private Feature2Component3, // private Feature2Component4, // private Feature2Component5, // private Feature2Component6, // private ], exports: [ Feature2Component5, // public Feature2Component6, // public ] }) export class Feature2Module { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

Slide 34

Slide 34 text

import { NgModule } from "@angular/core"; import { Feature1Module } from "./feature1-module/feature1.modu import { MyComponent } from "./feature1-module/my-component/my.component"; @NgModule({ imports: [ Feature1Module, Feature2Module ], declarations: [ AppComponent, MyComponent // DONT! ], bootstrap: [AppComponent] }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Slide 35

Slide 35 text

import { NgModule } from "@angular/core"; import { Feature1Module } from "./feature1-module/feature1.modu import { MyComponent } from "./feature1-module/my-component/my.component"; @NgModule({ imports: [ Feature1Module, Feature2Module ], declarations: [ AppComponent, MyComponent // DONT! ], bootstrap: [AppComponent] }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { MyComponent } from "./feature1-module/my-component/my.component"; MyComponent // DONT! import { NgModule } from "@angular/core"; 1 import { Feature1Module } from "./feature1-module/feature1.modu 2 3 4 5 6 @NgModule({ 7 imports: [ 8 Feature1Module, 9 Feature2Module 10 ], 11 declarations: [ 12 AppComponent, 13 14 ], 15 bootstrap: [AppComponent] 16 }) 17 export class AppModule {} 18

Slide 36

Slide 36 text

import { NgModule } from "@angular/core"; import { Feature1Module } from "./feature1-module/feature1.modu import { MyComponent } from "./feature1-module/my-component/my.component"; @NgModule({ imports: [ Feature1Module, Feature2Module ], declarations: [ AppComponent, MyComponent // DONT! ], bootstrap: [AppComponent] }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import { MyComponent } from "./feature1-module/my-component/my.component"; MyComponent // DONT! import { NgModule } from "@angular/core"; 1 import { Feature1Module } from "./feature1-module/feature1.modu 2 3 4 5 6 @NgModule({ 7 imports: [ 8 Feature1Module, 9 Feature2Module 10 ], 11 declarations: [ 12 AppComponent, 13 14 ], 15 bootstrap: [AppComponent] 16 }) 17 export class AppModule {} 18 import { NgModule } from "@angular/core"; import { Feature1Module } from "./feature1-module/feature1.modu import { MyComponent } from "./feature1-module/my-component/my.component"; @NgModule({ imports: [ Feature1Module, Feature2Module ], declarations: [ AppComponent, MyComponent // DONT! ], bootstrap: [AppComponent] }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Slide 37

Slide 37 text

Encapsulation

Slide 38

Slide 38 text

Libraries

Slide 39

Slide 39 text

Workspace

Slide 40

Slide 40 text

Workspace

Slide 41

Slide 41 text

Workspace

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

Workspace

Slide 45

Slide 45 text

Workspace

Slide 46

Slide 46 text

How to consume Libs?

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { /* ... */ } from 'lib-to-configure'; import { AppComponent } from './app.component'; export class AppModule {} 1 2 3 4 5 6 7 8

Slide 56

Slide 56 text

import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { /* ... */ } from 'lib-to-configure'; import { AppComponent } from './app.component'; export class AppModule {} 1 2 3 4 5 6 7 8 import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; 1 2 3 import { /* ... */ } from 'lib-to-configure'; 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8

Slide 57

Slide 57 text

import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { /* ... */ } from 'lib-to-configure'; import { AppComponent } from './app.component'; export class AppModule {} 1 2 3 4 5 6 7 8 import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; 1 2 3 import { /* ... */ } from 'lib-to-configure'; 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 import { /* ... */ } from 'lib-to-configure'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8

Slide 58

Slide 58 text

import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { /* ... */ } from 'lib-to-configure'; import { AppComponent } from './app.component'; export class AppModule {} 1 2 3 4 5 6 7 8 import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; 1 2 3 import { /* ... */ } from 'lib-to-configure'; 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 import { /* ... */ } from 'lib-to-configure'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 import { AppComponent } from './app.component'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 import { /* ... */ } from 'lib-to-configure'; 4 5 6 7 export class AppModule {} 8

Slide 59

Slide 59 text

import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { /* ... */ } from 'lib-to-configure'; import { AppComponent } from './app.component'; export class AppModule {} 1 2 3 4 5 6 7 8 import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; 1 2 3 import { /* ... */ } from 'lib-to-configure'; 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 import { /* ... */ } from 'lib-to-configure'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 import { AppComponent } from './app.component'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 import { /* ... */ } from 'lib-to-configure'; 4 5 6 7 export class AppModule {} 8 import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { /* ... */ } from 'lib-to-configure'; import { AppComponent } from './app.component'; export class AppModule {} 1 2 3 4 5 6 7 8

Slide 60

Slide 60 text

import { /* ... */ } from './../../../lib-to-configure/src/lib/lib-configuration'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8

Slide 61

Slide 61 text

import { /* ... */ } from './../../../lib-to-configure/src/lib/lib-configuration'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 Don't

Slide 62

Slide 62 text

import { /* ... */ } from 'lib-to-configure/public-api'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8

Slide 63

Slide 63 text

import { /* ... */ } from 'lib-to-configure/public-api'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { /* ... */ } from 'lib-to-configure/public-api'; import { AppComponent } from './app.component'; export class AppModule {} 1 2 3 4 5 6 7 8

Slide 64

Slide 64 text

import { /* ... */ } from 'lib-to-configure/public-api'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 Don't

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

import { /* ... */ } from 'lib-to-configure'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8 Do

Slide 67

Slide 67 text

import { /* ... */ } from 'lib-to-configure'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8

Slide 68

Slide 68 text

import { /* ... */ } from 'lib-to-configure'; import { NgModule, APP_INITIALIZER, Injectable } from '@angular/core'; 1 import { BrowserModule } from '@angular/platform-browser'; 2 3 4 5 import { AppComponent } from './app.component'; 6 7 export class AppModule {} 8

Slide 69

Slide 69 text

Abstraction

Slide 70

Slide 70 text

How to consume Libs

Slide 71

Slide 71 text

How to Con gure Libs?

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

Build once Deploy Everywhere

Slide 77

Slide 77 text

How to Con gure Libs?

Slide 78

Slide 78 text

@NgModule({ declarations: [LibToConfigureComponent], imports: [CommonModule], exports: [LibToConfigureComponent], }) export class LibToConfigureModule {} 1 2 3 4 5 6

Slide 79

Slide 79 text

@NgModule({ declarations: [LibToConfigureComponent], imports: [CommonModule], exports: [LibToConfigureComponent], }) export class LibToConfigureModule {} 1 2 3 4 5 6 @NgModule({ declarations: [AppComponent], imports: [BrowserModule, LibToConfigureModule], providers: [], bootstrap: [AppComponent], }) export class AppModule {} 1 2 3 4 5 6 7

Slide 80

Slide 80 text

static con g export class LibToConfigureConfiguration { name: string; } 1 2 3

Slide 81

Slide 81 text

static con g export class LibToConfigureConfiguration { name: string; } 1 2 3 export * from './lib/lib-configuration'; 1 export * from './lib/lib-to-configure.component'; 2 export * from './lib/lib-to-configure.module'; 3 export * from './lib/lib-to-configure.service'; 4

Slide 82

Slide 82 text

static con g @NgModule({ declarations: [LibToConfigureComponent], imports: [CommonModule], exports: [LibToConfigureComponent], }) export class LibToConfigureModule {} 1 2 3 4 5 6

Slide 83

Slide 83 text

static con g @NgModule({ /*...*/ }) export class LibToConfigureModule { static forRoot( libConfiguration: LibToConfigureConfiguration ): ModuleWithProviders { return { ngModule: LibToConfigureModule, providers: [ { provide: LibToConfigureConfiguration, useValue: libConfiguration, }, ], }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Slide 84

Slide 84 text

static con g @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, LibToConfigureModule.forRoot({ name: 'Fabian' }) ], providers: [], bootstrap: [AppComponent], }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10

Slide 85

Slide 85 text

Dynamic con g @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, LibToConfigureModule.forRoot( ??? ) ], providers: [], bootstrap: [AppComponent], }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10

Slide 86

Slide 86 text

Dynamic con g @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, LibToConfigureModule.forRoot( ??? ) ], providers: [ { provide: APP_INITIALIZER, useFactory: appInitializerFn, multi: true, deps: [AppConfigService], }, ], bootstrap: [AppComponent], }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Slide 87

Slide 87 text

Dynamic con g export class AppConfigService { private appConfig; constructor(private http: HttpClient) { } loadAppConfig() { return this.http.get('/assets/data/appConfig.json') .toPromise() .then(data => { this.appConfig = data; }); } getConfig() { return this.appConfig; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Slide 88

Slide 88 text

Dynamic con g const appInitializerFn = (appConfig: AppConfigService) => { return () => { return appConfig.loadAppConfig(); }; }; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, LibToConfigureModule, HttpClientModule ], providers: [ AppConfigService, { provide: APP_INITIALIZER, useFactory: appInitializerFn, multi: true, deps: [AppConfigService], }, ], bootstrap: [AppComponent], }) export class AppModule {} 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

Slide 89

Slide 89 text

Dynamic con g const appInitializerFn = (appConfig: AppConfigService) => { return () => { return appConfig.loadAppConfig(); }; }; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, LibToConfigureModule, HttpClientModule ], providers: [ AppConfigService, { provide: APP_INITIALIZER, useFactory: appInitializerFn, multi: true, deps: [AppConfigService], }, ], bootstrap: [AppComponent], }) export class AppModule {} 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 const appInitializerFn = (appConfig: AppConfigService) => { return () => { return appConfig.loadAppConfig(); }; }; 1 2 3 4 5 6 @NgModule({ 7 declarations: [AppComponent], 8 imports: [ 9 BrowserModule, 10 LibToConfigureModule, 11 HttpClientModule 12 ], 13 providers: [ 14 AppConfigService, 15 { 16 provide: APP_INITIALIZER, 17 useFactory: appInitializerFn, 18 multi: true, 19 deps: [AppConfigService], 20 }, 21 ], 22 bootstrap: [AppComponent], 23 }) 24 export class AppModule {} 25

Slide 90

Slide 90 text

Dynamic con g const appInitializerFn = (appConfig: AppConfigService) => { return () => { return appConfig.loadAppConfig(); }; }; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, LibToConfigureModule, HttpClientModule ], providers: [ AppConfigService, { provide: APP_INITIALIZER, useFactory: appInitializerFn, multi: true, deps: [AppConfigService], }, ], bootstrap: [AppComponent], }) export class AppModule {} 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 const appInitializerFn = (appConfig: AppConfigService) => { return () => { return appConfig.loadAppConfig(); }; }; 1 2 3 4 5 6 @NgModule({ 7 declarations: [AppComponent], 8 imports: [ 9 BrowserModule, 10 LibToConfigureModule, 11 HttpClientModule 12 ], 13 providers: [ 14 AppConfigService, 15 { 16 provide: APP_INITIALIZER, 17 useFactory: appInitializerFn, 18 multi: true, 19 deps: [AppConfigService], 20 }, 21 ], 22 bootstrap: [AppComponent], 23 }) 24 export class AppModule {} 25 useFactory: appInitializerFn, deps: [AppConfigService], const appInitializerFn = (appConfig: AppConfigService) => { 1 return () => { 2 return appConfig.loadAppConfig(); 3 }; 4 }; 5 6 @NgModule({ 7 declarations: [AppComponent], 8 imports: [ 9 BrowserModule, 10 LibToConfigureModule, 11 HttpClientModule 12 ], 13 providers: [ 14 AppConfigService, 15 { 16 provide: APP_INITIALIZER, 17 18 multi: true, 19 20 }, 21 ], 22 bootstrap: [AppComponent], 23 }) 24 export class AppModule {} 25

Slide 91

Slide 91 text

Dynamic con g LibToConfigureModule.forRoot(???), const appInitializerFn = (appConfig: AppConfigService) => { 1 return () => { 2 return appConfig.loadAppConfig(); 3 }; 4 }; 5 6 @NgModule({ 7 declarations: [AppComponent], 8 imports: [ 9 BrowserModule, 10 11 HttpClientModule 12 ], 13 providers: [ 14 AppConfigService, 15 { 16 provide: APP_INITIALIZER, 17 useFactory: appInitializerFn, 18 multi: true, 19 deps: [AppConfigService], 20 }, 21 ], 22 bootstrap: [AppComponent], 23 }) 24 export class AppModule {} 25

Slide 92

Slide 92 text

Dynamic con g

Slide 93

Slide 93 text

Dynamic con g export class LibToConfigureConfiguration { some: string = ''; } export class LibConfiguration { config?: Provider; } @Injectable({ providedIn: 'root' }) export abstract class LibConfigurationProvider { abstract get config(): LibToConfigureConfiguration; } @Injectable({ providedIn: 'root' }) export class DefaultLibConfiguration implements LibConfigurationProvider { get config(): LibToConfigureConfiguration { return { some: `Fallback` }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

Slide 94

Slide 94 text

Dynamic con g export class LibToConfigureConfiguration { some: string = ''; } export class LibConfiguration { config?: Provider; } @Injectable({ providedIn: 'root' }) export abstract class LibConfigurationProvider { abstract get config(): LibToConfigureConfiguration; } @Injectable({ providedIn: 'root' }) export class DefaultLibConfiguration implements LibConfigurationProvider { get config(): LibToConfigureConfiguration { return { some: `Fallback` }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 export class LibToConfigureConfiguration { some: string = ''; } 1 2 3 4 export class LibConfiguration { 5 config?: Provider; 6 } 7 8 @Injectable({ providedIn: 'root' }) 9 export abstract class LibConfigurationProvider { 10 abstract get config(): LibToConfigureConfiguration; 11 } 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21

Slide 95

Slide 95 text

Dynamic con g export class LibToConfigureConfiguration { some: string = ''; } export class LibConfiguration { config?: Provider; } @Injectable({ providedIn: 'root' }) export abstract class LibConfigurationProvider { abstract get config(): LibToConfigureConfiguration; } @Injectable({ providedIn: 'root' }) export class DefaultLibConfiguration implements LibConfigurationProvider { get config(): LibToConfigureConfiguration { return { some: `Fallback` }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 export class LibToConfigureConfiguration { some: string = ''; } 1 2 3 4 export class LibConfiguration { 5 config?: Provider; 6 } 7 8 @Injectable({ providedIn: 'root' }) 9 export abstract class LibConfigurationProvider { 10 abstract get config(): LibToConfigureConfiguration; 11 } 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21 export class LibConfiguration { config?: Provider; } export class LibToConfigureConfiguration { 1 some: string = ''; 2 } 3 4 5 6 7 8 @Injectable({ providedIn: 'root' }) 9 export abstract class LibConfigurationProvider { 10 abstract get config(): LibToConfigureConfiguration; 11 } 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21

Slide 96

Slide 96 text

Dynamic con g export class LibToConfigureConfiguration { some: string = ''; } export class LibConfiguration { config?: Provider; } @Injectable({ providedIn: 'root' }) export abstract class LibConfigurationProvider { abstract get config(): LibToConfigureConfiguration; } @Injectable({ providedIn: 'root' }) export class DefaultLibConfiguration implements LibConfigurationProvider { get config(): LibToConfigureConfiguration { return { some: `Fallback` }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 export class LibToConfigureConfiguration { some: string = ''; } 1 2 3 4 export class LibConfiguration { 5 config?: Provider; 6 } 7 8 @Injectable({ providedIn: 'root' }) 9 export abstract class LibConfigurationProvider { 10 abstract get config(): LibToConfigureConfiguration; 11 } 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21 export class LibConfiguration { config?: Provider; } export class LibToConfigureConfiguration { 1 some: string = ''; 2 } 3 4 5 6 7 8 @Injectable({ providedIn: 'root' }) 9 export abstract class LibConfigurationProvider { 10 abstract get config(): LibToConfigureConfiguration; 11 } 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21 @Injectable({ providedIn: 'root' }) export abstract class LibConfigurationProvider { abstract get config(): LibToConfigureConfiguration; } export class LibToConfigureConfiguration { 1 some: string = ''; 2 } 3 4 export class LibConfiguration { 5 config?: Provider; 6 } 7 8 9 10 11 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21

Slide 97

Slide 97 text

Dynamic con g export class LibToConfigureConfiguration { some: string = ''; } export class LibConfiguration { config?: Provider; } @Injectable({ providedIn: 'root' }) export abstract class LibConfigurationProvider { abstract get config(): LibToConfigureConfiguration; } @Injectable({ providedIn: 'root' }) export class DefaultLibConfiguration implements LibConfigurationProvider { get config(): LibToConfigureConfiguration { return { some: `Fallback` }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 export class LibToConfigureConfiguration { some: string = ''; } 1 2 3 4 export class LibConfiguration { 5 config?: Provider; 6 } 7 8 @Injectable({ providedIn: 'root' }) 9 export abstract class LibConfigurationProvider { 10 abstract get config(): LibToConfigureConfiguration; 11 } 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21 export class LibConfiguration { config?: Provider; } export class LibToConfigureConfiguration { 1 some: string = ''; 2 } 3 4 5 6 7 8 @Injectable({ providedIn: 'root' }) 9 export abstract class LibConfigurationProvider { 10 abstract get config(): LibToConfigureConfiguration; 11 } 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21 @Injectable({ providedIn: 'root' }) export abstract class LibConfigurationProvider { abstract get config(): LibToConfigureConfiguration; } export class LibToConfigureConfiguration { 1 some: string = ''; 2 } 3 4 export class LibConfiguration { 5 config?: Provider; 6 } 7 8 9 10 11 12 13 @Injectable({ providedIn: 'root' }) 14 export class DefaultLibConfiguration 15 implements LibConfigurationProvider { 16 17 get config(): LibToConfigureConfiguration { 18 return { some: `Fallback` }; 19 } 20 } 21 @Injectable({ providedIn: 'root' }) export class DefaultLibConfiguration implements LibConfigurationProvider { get config(): LibToConfigureConfiguration { return { some: `Fallback` }; } export class LibToConfigureConfiguration { 1 some: string = ''; 2 } 3 4 export class LibConfiguration { 5 config?: Provider; 6 } 7 8 @Injectable({ providedIn: 'root' }) 9 export abstract class LibConfigurationProvider { 10 abstract get config(): LibToConfigureConfiguration; 11 } 12 13 14 15 16 17 18 19 20 } 21

Slide 98

Slide 98 text

Dynamic con g @NgModule({ /*...*/ }) export class LibToConfigureModule { static forRoot( libModuleConfiguration: LibConfiguration = {} ): ModuleWithProviders { return { ngModule: LibToConfigureModule, providers: [ libModuleConfiguration.config || { provide: LibConfigurationProvider, useClass: DefaultLibConfiguration, }, ], }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Slide 99

Slide 99 text

Dynamic con g @NgModule({ /*...*/ }) export class LibToConfigureModule { static forRoot( libModuleConfiguration: LibConfiguration = {} ): ModuleWithProviders { return { ngModule: LibToConfigureModule, providers: [ libModuleConfiguration.config || { provide: LibConfigurationProvider, useClass: DefaultLibConfiguration, }, ], }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 libModuleConfiguration: LibConfiguration = {} libModuleConfiguration.config || { @NgModule({ 1 /*...*/ 2 }) 3 export class LibToConfigureModule { 4 static forRoot( 5 6 ): ModuleWithProviders { 7 return { 8 ngModule: LibToConfigureModule, 9 providers: [ 10 11 provide: LibConfigurationProvider, 12 useClass: DefaultLibConfiguration, 13 }, 14 ], 15 }; 16 } 17 } 18

Slide 100

Slide 100 text

Dynamic con g @NgModule({ /*...*/ }) export class LibToConfigureModule { static forRoot( libModuleConfiguration: LibConfiguration = {} ): ModuleWithProviders { return { ngModule: LibToConfigureModule, providers: [ libModuleConfiguration.config || { provide: LibConfigurationProvider, useClass: DefaultLibConfiguration, }, ], }; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 libModuleConfiguration: LibConfiguration = {} libModuleConfiguration.config || { @NgModule({ 1 /*...*/ 2 }) 3 export class LibToConfigureModule { 4 static forRoot( 5 6 ): ModuleWithProviders { 7 return { 8 ngModule: LibToConfigureModule, 9 providers: [ 10 11 provide: LibConfigurationProvider, 12 useClass: DefaultLibConfiguration, 13 }, 14 ], 15 }; 16 } 17 } 18 provide: LibConfigurationProvider, useClass: DefaultLibConfiguration, @NgModule({ 1 /*...*/ 2 }) 3 export class LibToConfigureModule { 4 static forRoot( 5 libModuleConfiguration: LibConfiguration = {} 6 ): ModuleWithProviders { 7 return { 8 ngModule: LibToConfigureModule, 9 providers: [ 10 libModuleConfiguration.config || { 11 12 13 }, 14 ], 15 }; 16 } 17 } 18

Slide 101

Slide 101 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { private internalConfig: LibToConfigureConfiguration; setConfig(config: LibToConfigureConfiguration) { this.internalConfig = config; } getConfig() { return this.internalConfig; } } @NgModule({ /* .. */ }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Slide 102

Slide 102 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { private internalConfig: LibToConfigureConfiguration; setConfig(config: LibToConfigureConfiguration) { this.internalConfig = config; } getConfig() { return this.internalConfig; } } @NgModule({ /* .. */ }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Injectable({ providedIn: 'root' }) export class ConfigurationStore { private internalConfig: LibToConfigureConfiguration; setConfig(config: LibToConfigureConfiguration) { this.internalConfig = config; } getConfig() { return this.internalConfig; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 @NgModule({ 14 /* .. */ 15 }) 16 export class AppModule {} 17

Slide 103

Slide 103 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { ... } export function initApp(configurationStore: ConfigurationStore) { return () => { return new Promise((resolve) => { setTimeout(() => { configurationStore.setConfig({ some: 'Fabian' }); resolve(); }, 2000); }); }; } @NgModule({ /* .. */ }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Slide 104

Slide 104 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { ... } export function initApp(configurationStore: ConfigurationStore) { return () => { return new Promise((resolve) => { setTimeout(() => { configurationStore.setConfig({ some: 'Fabian' }); resolve(); }, 2000); }); }; } @NgModule({ /* .. */ }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 export function initApp(configurationStore: ConfigurationStore) { return () => { return new Promise((resolve) => { setTimeout(() => { configurationStore.setConfig({ some: 'Fabian' }); resolve(); }, 2000); }); }; } @Injectable({ providedIn: 'root' }) 1 export class ConfigurationStore { ... } 2 3 4 5 6 7 8 9 10 11 12 13 14 @NgModule({ 15 /* .. */ 16 }) 17 export class AppModule {} 18

Slide 105

Slide 105 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { ... } export function initApp(configurationStore: ConfigurationStore) { ...} @Injectable({ providedIn: 'root' }) export class ConfigFromApp implements LibConfigurationProvider { constructor(private configStore: ConfigurationStore) {} get config(): LibToConfigureConfiguration { return this.configStore.getConfig(); } } @NgModule({ /* .. */ }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Slide 106

Slide 106 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { ... } export function initApp(configurationStore: ConfigurationStore) { ...} @Injectable({ providedIn: 'root' }) export class ConfigFromApp implements LibConfigurationProvider { constructor(private configStore: ConfigurationStore) {} get config(): LibToConfigureConfiguration { return this.configStore.getConfig(); } } @NgModule({ /* .. */ }) export class AppModule {} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Injectable({ providedIn: 'root' }) export class ConfigFromApp implements LibConfigurationProvider { constructor(private configStore: ConfigurationStore) {} get config(): LibToConfigureConfiguration { return this.configStore.getConfig(); } } @Injectable({ providedIn: 'root' }) 1 export class ConfigurationStore { ... } 2 3 export function initApp(configurationStore: ConfigurationStore) { ...} 4 5 6 7 8 9 10 11 12 13 14 @NgModule({ 15 /* .. */ 16 }) 17 export class AppModule {} 18

Slide 107

Slide 107 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { ... } export function initApp(configurationStore: ConfigurationStore) { ...} @Injectable({ providedIn: 'root' }) export class ConfigFromApp implements LibConfigurationProvider { ... } @NgModule({ imports: [ LibToConfigureModule.forRoot({ config: { provide: LibConfigurationProvider, useClass: ConfigFromApp, }, }), ], providers: [ { provide: APP_INITIALIZER, useFactory: initApp, multi: true, deps: [ConfigurationStore], }, ], bootstrap: [AppComponent], }) export class AppModule {} 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

Slide 108

Slide 108 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { ... } export function initApp(configurationStore: ConfigurationStore) { ...} @Injectable({ providedIn: 'root' }) export class ConfigFromApp implements LibConfigurationProvider { ... } @NgModule({ imports: [ LibToConfigureModule.forRoot({ config: { provide: LibConfigurationProvider, useClass: ConfigFromApp, }, }), ], providers: [ { provide: APP_INITIALIZER, useFactory: initApp, multi: true, deps: [ConfigurationStore], }, ], bootstrap: [AppComponent], }) export class AppModule {} 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 LibToConfigureModule.forRoot({ config: { provide: LibConfigurationProvider, useClass: ConfigFromApp, }, }), @Injectable({ providedIn: 'root' }) 1 export class ConfigurationStore { ... } 2 3 export function initApp(configurationStore: ConfigurationStore) { ...} 4 5 @Injectable({ providedIn: 'root' }) 6 export class ConfigFromApp implements LibConfigurationProvider { ... } 7 8 @NgModule({ 9 imports: [ 10 11 12 13 14 15 16 ], 17 providers: [ 18 { 19 provide: APP_INITIALIZER, 20 useFactory: initApp, 21 multi: true, 22 deps: [ConfigurationStore], 23 }, 24 ], 25 bootstrap: [AppComponent], 26 }) 27 export class AppModule {} 28

Slide 109

Slide 109 text

Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore { ... } export function initApp(configurationStore: ConfigurationStore) { ...} @Injectable({ providedIn: 'root' }) export class ConfigFromApp implements LibConfigurationProvider { ... } @NgModule({ imports: [ LibToConfigureModule.forRoot({ config: { provide: LibConfigurationProvider, useClass: ConfigFromApp, }, }), ], providers: [ { provide: APP_INITIALIZER, useFactory: initApp, multi: true, deps: [ConfigurationStore], }, ], bootstrap: [AppComponent], }) export class AppModule {} 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 LibToConfigureModule.forRoot({ config: { provide: LibConfigurationProvider, useClass: ConfigFromApp, }, }), @Injectable({ providedIn: 'root' }) 1 export class ConfigurationStore { ... } 2 3 export function initApp(configurationStore: ConfigurationStore) { ...} 4 5 @Injectable({ providedIn: 'root' }) 6 export class ConfigFromApp implements LibConfigurationProvider { ... } 7 8 @NgModule({ 9 imports: [ 10 11 12 13 14 15 16 ], 17 providers: [ 18 { 19 provide: APP_INITIALIZER, 20 useFactory: initApp, 21 multi: true, 22 deps: [ConfigurationStore], 23 }, 24 ], 25 bootstrap: [AppComponent], 26 }) 27 export class AppModule {} 28 { provide: APP_INITIALIZER, useFactory: initApp, multi: true, deps: [ConfigurationStore], }, @Injectable({ providedIn: 'root' }) 1 export class ConfigurationStore { ... } 2 3 export function initApp(configurationStore: ConfigurationStore) { ...} 4 5 @Injectable({ providedIn: 'root' }) 6 export class ConfigFromApp implements LibConfigurationProvider { ... } 7 8 @NgModule({ 9 imports: [ 10 LibToConfigureModule.forRoot({ 11 config: { 12 provide: LibConfigurationProvider, 13 useClass: ConfigFromApp, 14 }, 15 }), 16 ], 17 providers: [ 18 19 20 21 22 23 24 ], 25 bootstrap: [AppComponent], 26 }) 27 export class AppModule {} 28

Slide 110

Slide 110 text

https://github.com/FabianGosebrink/angular-library-configuration

Slide 111

Slide 111 text

https://bit.ly/32lPE4a

Slide 112

Slide 112 text

Eager Loaded Lazy Loaded

Slide 113

Slide 113 text

1. Load my con g

Slide 114

Slide 114 text

1. Load my con g 2. start my app

Slide 115

Slide 115 text

Main.ts import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic() .bootstrapModule(AppModule) .catch((err) => console.error(err)); 1 2 3 4 5 6 7 8 9 10 11 12 https://timdeschryver.dev/blog/angular-build-once-deploy-to-multiple-environments

Slide 116

Slide 116 text

Main.ts fetch('/assets/config.json') import { enableProdMode } from '@angular/core' 1 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 2 import { environment } from './environments/environment' 3 import { AppConfig, APP_CONFIG } from './app.config' 4 import { AppModule } from './app/app.module' 5 6 7 .then((response) => response.json()) 8 .then((config) => { 9 if (environment.production) { 10 enableProdMode() 11 } 12 13 platformBrowserDynamic([{ provide: APP_CONFIG, useValue: config }]) 14 .bootstrapModule(AppModule) 15 .catch((err) => console.error(err)) 16 }) 17

Slide 117

Slide 117 text

Main.ts fetch('/assets/config.json') import { enableProdMode } from '@angular/core' 1 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 2 import { environment } from './environments/environment' 3 import { AppConfig, APP_CONFIG } from './app.config' 4 import { AppModule } from './app/app.module' 5 6 7 .then((response) => response.json()) 8 .then((config) => { 9 if (environment.production) { 10 enableProdMode() 11 } 12 13 platformBrowserDynamic([{ provide: APP_CONFIG, useValue: config }]) 14 .bootstrapModule(AppModule) 15 .catch((err) => console.error(err)) 16 }) 17 .then((response) => response.json()) import { enableProdMode } from '@angular/core' 1 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 2 import { environment } from './environments/environment' 3 import { AppConfig, APP_CONFIG } from './app.config' 4 import { AppModule } from './app/app.module' 5 6 fetch('/assets/config.json') 7 8 .then((config) => { 9 if (environment.production) { 10 enableProdMode() 11 } 12 13 platformBrowserDynamic([{ provide: APP_CONFIG, useValue: config }]) 14 .bootstrapModule(AppModule) 15 .catch((err) => console.error(err)) 16 }) 17

Slide 118

Slide 118 text

Main.ts fetch('/assets/config.json') import { enableProdMode } from '@angular/core' 1 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 2 import { environment } from './environments/environment' 3 import { AppConfig, APP_CONFIG } from './app.config' 4 import { AppModule } from './app/app.module' 5 6 7 .then((response) => response.json()) 8 .then((config) => { 9 if (environment.production) { 10 enableProdMode() 11 } 12 13 platformBrowserDynamic([{ provide: APP_CONFIG, useValue: config }]) 14 .bootstrapModule(AppModule) 15 .catch((err) => console.error(err)) 16 }) 17 .then((response) => response.json()) import { enableProdMode } from '@angular/core' 1 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 2 import { environment } from './environments/environment' 3 import { AppConfig, APP_CONFIG } from './app.config' 4 import { AppModule } from './app/app.module' 5 6 fetch('/assets/config.json') 7 8 .then((config) => { 9 if (environment.production) { 10 enableProdMode() 11 } 12 13 platformBrowserDynamic([{ provide: APP_CONFIG, useValue: config }]) 14 .bootstrapModule(AppModule) 15 .catch((err) => console.error(err)) 16 }) 17 platformBrowserDynamic([{ provide: APP_CONFIG, useValue: config }]) import { enableProdMode } from '@angular/core' 1 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 2 import { environment } from './environments/environment' 3 import { AppConfig, APP_CONFIG } from './app.config' 4 import { AppModule } from './app/app.module' 5 6 fetch('/assets/config.json') 7 .then((response) => response.json()) 8 .then((config) => { 9 if (environment.production) { 10 enableProdMode() 11 } 12 13 14 .bootstrapModule(AppModule) 15 .catch((err) => console.error(err)) 16 }) 17

Slide 119

Slide 119 text

Main.ts export class AppConfig { /* */ } export let APP_CONFIG = new InjectionToken('APP_CONFIG') 1 2 3 4 5

Slide 120

Slide 120 text

Main.ts export class AppConfig { /* */ } export let APP_CONFIG = new InjectionToken('APP_CONFIG') 1 2 3 4 5 import { APP_CONFIG, AppConfig } from '...'; @Injectable({ providedIn: 'root' }) export class MyService constructor(@Inject(APP_CONFIG) private config: AppConfig) {} } 1 2 3 4 5 6 7

Slide 121

Slide 121 text

No content

Slide 122

Slide 122 text

No content

Slide 123

Slide 123 text

No content

Slide 124

Slide 124 text

No content

Slide 125

Slide 125 text

Monorepos

Slide 126

Slide 126 text

Rethinking Libraries

Slide 127

Slide 127 text

Library Share COde over x apps

Slide 128

Slide 128 text

Library Share COde over x apps parts of a feature!

Slide 129

Slide 129 text

Feature Feature Ui Data access Utils

Slide 130

Slide 130 text

No content

Slide 131

Slide 131 text

No content

Slide 132

Slide 132 text

Folders

Slide 133

Slide 133 text

Lib: Api Lib: Data Lib: Ui Lib: Util Lib: Feature

Slide 134

Slide 134 text

Folders Lib: Api Lib: Data Lib: Ui Lib: Util Lib: Feature

Slide 135

Slide 135 text

Ui Feature vs.

Slide 136

Slide 136 text

Ui Feature vs.

Slide 137

Slide 137 text

Feature Ui vs.

Slide 138

Slide 138 text

Container Presentational vs.

Slide 139

Slide 139 text

Smart Dumb vs.

Slide 140

Slide 140 text

Stateful Stateless vs.

Slide 141

Slide 141 text

Stateful import { /* ... */ } from '...'; @Component({ selector: 'workspace-groups-meetups-list', templateUrl: './groups-meetups-list.component.html', styleUrls: ['./groups-meetups-list.component.scss'], }) export class GroupsMeetupsListComponent implements OnInit { items$: Observable; loading$: Observable; constructor(private store: Store) {} ngOnInit() { this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

Slide 142

Slide 142 text

Stateful import { /* ... */ } from '...'; @Component({ selector: 'workspace-groups-meetups-list', templateUrl: './groups-meetups-list.component.html', styleUrls: ['./groups-meetups-list.component.scss'], }) export class GroupsMeetupsListComponent implements OnInit { items$: Observable; loading$: Observable; constructor(private store: Store) {} ngOnInit() { this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 items$: Observable; loading$: Observable; import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 9 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21

Slide 143

Slide 143 text

Stateful import { /* ... */ } from '...'; @Component({ selector: 'workspace-groups-meetups-list', templateUrl: './groups-meetups-list.component.html', styleUrls: ['./groups-meetups-list.component.scss'], }) export class GroupsMeetupsListComponent implements OnInit { items$: Observable; loading$: Observable; constructor(private store: Store) {} ngOnInit() { this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 items$: Observable; loading$: Observable; import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 9 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 constructor(private store: Store) {} import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21

Slide 144

Slide 144 text

Stateful import { /* ... */ } from '...'; @Component({ selector: 'workspace-groups-meetups-list', templateUrl: './groups-meetups-list.component.html', styleUrls: ['./groups-meetups-list.component.scss'], }) export class GroupsMeetupsListComponent implements OnInit { items$: Observable; loading$: Observable; constructor(private store: Store) {} ngOnInit() { this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 items$: Observable; loading$: Observable; import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 9 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 constructor(private store: Store) {} import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 15 16 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21

Slide 145

Slide 145 text

Stateful import { /* ... */ } from '...'; @Component({ selector: 'workspace-groups-meetups-list', templateUrl: './groups-meetups-list.component.html', styleUrls: ['./groups-meetups-list.component.scss'], }) export class GroupsMeetupsListComponent implements OnInit { items$: Observable; loading$: Observable; constructor(private store: Store) {} ngOnInit() { this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 items$: Observable; loading$: Observable; import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 9 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 constructor(private store: Store) {} import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 15 16 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 19 } 20 } 21

Slide 146

Slide 146 text

Stateful import { /* ... */ } from '...'; @Component({ selector: 'workspace-groups-meetups-list', templateUrl: './groups-meetups-list.component.html', styleUrls: ['./groups-meetups-list.component.scss'], }) export class GroupsMeetupsListComponent implements OnInit { items$: Observable; loading$: Observable; constructor(private store: Store) {} ngOnInit() { this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 items$: Observable; loading$: Observable; import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 9 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 constructor(private store: Store) {} import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 15 16 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); import { /* ... */ } from '...'; 1 2 @Component({ 3 selector: 'workspace-groups-meetups-list', 4 templateUrl: './groups-meetups-list.component.html', 5 styleUrls: ['./groups-meetups-list.component.scss'], 6 }) 7 export class GroupsMeetupsListComponent implements OnInit { 8 items$: Observable; 9 loading$: Observable; 10 11 constructor(private store: Store) {} 12 13 ngOnInit() { 14 this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); 15 16 this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); 17 18 19 } 20 } 21 import { /* ... */ } from '...'; @Component({ selector: 'workspace-groups-meetups-list', templateUrl: './groups-meetups-list.component.html', styleUrls: ['./groups-meetups-list.component.scss'], }) export class GroupsMeetupsListComponent implements OnInit { items$: Observable; loading$: Observable; constructor(private store: Store) {} ngOnInit() { this.loading$ = this.store.pipe(select(fromGroupStore.selectIsLoading)); this.items$ = this.store.pipe(select(fromGroupStore.selectAllMeetups)); this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

Slide 147

Slide 147 text

Stateful

All Gatherings of the Group

1 2 3 4 5 6 7 8 9 10 11 12 13

Slide 148

Slide 148 text

Stateful

All Gatherings of the Group

1 2 3 4 5 6 7 8 9 10 11 12 13
1

All Gatherings of the Group

2 3 7 8 9 10 11 12
13

Slide 149

Slide 149 text

Stateless import { /* ... */ } from '...'; @Component({ selector: 'workspace-meetup-list', templateUrl: './meetup-list.component.html', styleUrls: ['./meetup-list.component.scss'], }) export class MeetupListComponent { @Input() items: Meetup[] = []; } 1 2 3 4 5 6 7 8 9 10 11 12

Slide 150

Slide 150 text

Stateless
No items found...
  • {{ item.name }}
1 2 3 4 5 6 7 8 9 10 11 12 13 14

Slide 151

Slide 151 text

Stateless
No items found...
1 2 3 4 5 6 7 8 9 10 11 12 13

Slide 152

Slide 152 text

Stateless
No items found...
1 2 3 4 5 6 7 8 9 10 11 12 13 14

Slide 153

Slide 153 text

Stateless
No items found...
1 2 3 4 5 6 7 8 9 10 11 12 13 14

Slide 154

Slide 154 text

Stateless import { /* ... */ } from '...'; @Component({ selector: 'workspace-meetup-list', templateUrl: './meetup-list.component.html', styleUrls: ['./meetup-list.component.scss'], }) export class MeetupListComponent { @Input() items: Meetup[] = []; @Output() itemClicked = new EventEmitter(); bubbleNavigationEvent(meetup: Meetup) { this.itemClicked.emit(meetup); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Slide 155

Slide 155 text

Stateful Stateless [ ... ] ( ... )

Slide 156

Slide 156 text

Stateful Stateless [ ... ] ( ... ) Stateless [ ... ] ( ... )

Slide 157

Slide 157 text

Stateful Stateless [ ... ] ( ... ) Stateless [ ... ] ( ... )

Slide 158

Slide 158 text

Stateful Stateless [ ... ] ( ... ) Stateless [ ... ] ( ... ) Service

Slide 159

Slide 159 text

Service @Injectable({ providedIn: 'root' }) export class MyService { // DON'T somethingHappened = new EventEmitter(); throwSomethingHappened(data: any) { this.somethingHappened.emit(data); } } 1 2 3 4 5 6 7 8 9 10 somethingHappened.subscribe(data => ...) 1

Slide 160

Slide 160 text

Service @Injectable({ providedIn: 'root' }) export class MyService { // DON'T somethingHappened = new Subject(); throwSomethingHappened(data: any) { this.somethingHappened.next(data); } } 1 2 3 4 5 6 7 8 9 10 somethingHappened.subscribe(data => ...) 1

Slide 161

Slide 161 text

Service @Injectable({ providedIn: 'root' }) export class MyService { private somethingHappenedInternal = new Subject(); get somethingHappened() { return this.somethingHappenedInternal.asObservable(); } throwSomethingHappened(data: any) { this.somethingHappened.next(data); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 somethingHappened.subscribe(data => ...) 1

Slide 162

Slide 162 text

Service @Injectable({ providedIn: 'root' }) export class MyService { private somethingHappenedInternal = new Subject(); get somethingHappened() { return this.somethingHappenedInternal.asObservable(); } throwSomethingHappened(data: any) { this.somethingHappened.next(data); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 private somethingHappenedInternal = new Subject(); @Injectable({ providedIn: 'root' }) 1 export class MyService { 2 3 4 5 get somethingHappened() { 6 return this.somethingHappenedInternal.asObservable(); 7 } 8 9 throwSomethingHappened(data: any) { 10 this.somethingHappened.next(data); 11 } 12 } 13 somethingHappened.subscribe(data => ...) 1

Slide 163

Slide 163 text

Service @Injectable({ providedIn: 'root' }) export class MyService { private somethingHappenedInternal = new Subject(); get somethingHappened() { return this.somethingHappenedInternal.asObservable(); } throwSomethingHappened(data: any) { this.somethingHappened.next(data); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 private somethingHappenedInternal = new Subject(); @Injectable({ providedIn: 'root' }) 1 export class MyService { 2 3 4 5 get somethingHappened() { 6 return this.somethingHappenedInternal.asObservable(); 7 } 8 9 throwSomethingHappened(data: any) { 10 this.somethingHappened.next(data); 11 } 12 } 13 get somethingHappened() { return this.somethingHappenedInternal.asObservable(); } @Injectable({ providedIn: 'root' }) 1 export class MyService { 2 3 private somethingHappenedInternal = new Subject(); 4 5 6 7 8 9 throwSomethingHappened(data: any) { 10 this.somethingHappened.next(data); 11 } 12 } 13 somethingHappened.subscribe(data => ...) 1

Slide 164

Slide 164 text

Service @Injectable({ providedIn: 'root' }) export class MyService { private somethingHappenedInternal = new Subject(); get somethingHappened() { return this.somethingHappenedInternal.asObservable(); } throwSomethingHappened(data: any) { this.somethingHappened.next(data); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 private somethingHappenedInternal = new Subject(); @Injectable({ providedIn: 'root' }) 1 export class MyService { 2 3 4 5 get somethingHappened() { 6 return this.somethingHappenedInternal.asObservable(); 7 } 8 9 throwSomethingHappened(data: any) { 10 this.somethingHappened.next(data); 11 } 12 } 13 get somethingHappened() { return this.somethingHappenedInternal.asObservable(); } @Injectable({ providedIn: 'root' }) 1 export class MyService { 2 3 private somethingHappenedInternal = new Subject(); 4 5 6 7 8 9 throwSomethingHappened(data: any) { 10 this.somethingHappened.next(data); 11 } 12 } 13 @Injectable({ providedIn: 'root' }) export class MyService { private somethingHappenedInternal = new Subject(); get somethingHappened() { return this.somethingHappenedInternal.asObservable(); } throwSomethingHappened(data: any) { this.somethingHappened.next(data); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 somethingHappened.subscribe(data => ...) 1

Slide 165

Slide 165 text

RxJs

Slide 166

Slide 166 text

"if you're starting with angular, you do not need an angular course, you need an rxjs course"

Slide 167

Slide 167 text

"if you're starting with angular, you do not need an angular course, you need an rxjs course" Colleague - some time ago

Slide 168

Slide 168 text

Tap Map SwitchMap MergeMap ConcatMap ExhaustMap

Slide 169

Slide 169 text

Keep the stream

Slide 170

Slide 170 text

.Subscribe() Does not keep the stream

Slide 171

Slide 171 text

@Component({ selector: "my-app", template: `{{ todos | json }}` }) export class AppComponent implements OnInit { todos: any[]; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get("https://...") .subscribe(result => { this.todos = result; }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Slide 172

Slide 172 text

@Component({ selector: "my-app", template: `{{ todos | json }}` }) export class AppComponent implements OnInit { todos: any[]; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get("https://...") .subscribe(result => { this.todos = result; }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template: `{{ todos | json }}` todos: any[]; @Component({ 1 selector: "my-app", 2 3 }) 4 export class AppComponent implements OnInit { 5 6 7 constructor(private http: HttpClient) {} 8 9 ngOnInit(): void { 10 this.http 11 .get("https://...") 12 .subscribe(result => { 13 this.todos = result; 14 }); 15 } 16 } 17

Slide 173

Slide 173 text

@Component({ selector: "my-app", template: `{{ todos | json }}` }) export class AppComponent implements OnInit { todos: any[]; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get("https://...") .subscribe(result => { this.todos = result; }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template: `{{ todos | json }}` todos: any[]; @Component({ 1 selector: "my-app", 2 3 }) 4 export class AppComponent implements OnInit { 5 6 7 constructor(private http: HttpClient) {} 8 9 ngOnInit(): void { 10 this.http 11 .get("https://...") 12 .subscribe(result => { 13 this.todos = result; 14 }); 15 } 16 } 17 ngOnInit(): void { this.http .get("https://...") .subscribe(result => { this.todos = result; }); } @Component({ 1 selector: "my-app", 2 template: `{{ todos | json }}` 3 }) 4 export class AppComponent implements OnInit { 5 todos: any[]; 6 7 constructor(private http: HttpClient) {} 8 9 10 11 12 13 14 15 16 } 17

Slide 174

Slide 174 text

.subscribe(result => this.todos = result); @Component({ 1 selector: "my-app", 2 template: `{{ todos | json }}` 3 }) 4 export class AppComponent implements OnInit { 5 todos: any[]; 6 7 constructor(private http: HttpClient) {} 8 9 ngOnInit(): void { 10 this.http 11 .get("https://...") 12 13 } 14 } 15

Slide 175

Slide 175 text

@Component({ selector: "my-app", template: `{{ todos$ | async | json }}`, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todos$: Observable; constructor(private http: HttpClient) {} ngOnInit(): void { this.todos$ = this.http.get("https://...") } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Slide 176

Slide 176 text

@Component({ selector: "my-app", template: `{{ todos$ | async | json }}`, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todos$: Observable; constructor(private http: HttpClient) {} ngOnInit(): void { this.todos$ = this.http.get("https://...") } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template: `{{ todos$ | async | json }}`, ngOnInit(): void { this.todos$ = this.http.get("https://...") @Component({ 1 selector: "my-app", 2 3 styleUrls: ["./app.component.css"] 4 }) 5 export class AppComponent implements OnInit { 6 todos$: Observable; 7 8 constructor(private http: HttpClient) {} 9 10 11 12 13 } 14 } 15

Slide 177

Slide 177 text

ngOnInit(): void { this.todos$ = this.http.get("https://...") .pipe(tap(result => console.log(result))); @Component({ 1 selector: "my-app", 2 template: `{{ todos$ | async | json }}`, 3 styleUrls: ["./app.component.css"] 4 }) 5 export class AppComponent implements OnInit { 6 todos$: Observable; 7 8 constructor(private http: HttpClient) {} 9 10 11 12 13 } 14 } 15

Slide 178

Slide 178 text

@Component({ selector: "my-app", template: `{{ todos$ | async | json }}`, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todos$: Observable; constructor(private http: HttpClient) {} ngOnInit(): void { this.todos$ = this.http.get("https://...") .pipe(map(result => result.length)); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Slide 179

Slide 179 text

@Component({ selector: "my-app", template: `{{ todos$ | async | json }}`, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todos$: Observable; constructor(private http: HttpClient) {} ngOnInit(): void { this.todos$ = this.http.get("https://...") .pipe(map(result => result.length)); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template: `{{ todos$ | async | json }}`, todos$: Observable; @Component({ 1 selector: "my-app", 2 3 styleUrls: ["./app.component.css"] 4 }) 5 export class AppComponent implements OnInit { 6 7 8 constructor(private http: HttpClient) {} 9 10 ngOnInit(): void { 11 this.todos$ = this.http.get("https://...") 12 .pipe(map(result => result.length)); 13 } 14 } 15

Slide 180

Slide 180 text

@Component({ selector: "my-app", template: `{{ todos$ | async | json }}`, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todos$: Observable; constructor(private http: HttpClient) {} ngOnInit(): void { this.todos$ = this.http.get("https://...") .pipe(map(result => result.length)); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template: `{{ todos$ | async | json }}`, todos$: Observable; @Component({ 1 selector: "my-app", 2 3 styleUrls: ["./app.component.css"] 4 }) 5 export class AppComponent implements OnInit { 6 7 8 constructor(private http: HttpClient) {} 9 10 ngOnInit(): void { 11 this.todos$ = this.http.get("https://...") 12 .pipe(map(result => result.length)); 13 } 14 } 15 ngOnInit(): void { this.todos$ = this.http.get("https://...") .pipe(map(result => result.length)); @Component({ 1 selector: "my-app", 2 template: `{{ todos$ | async | json }}`, 3 styleUrls: ["./app.component.css"] 4 }) 5 export class AppComponent implements OnInit { 6 todos$: Observable; 7 8 constructor(private http: HttpClient) {} 9 10 11 12 13 } 14 } 15

Slide 181

Slide 181 text

@Component({ selector: "my-app", template: `{{ todos$ | async | json }}`, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todos$: Observable; constructor(private http: HttpClient) {} ngOnInit(): void { this.todos$ = this.http.get("https://...") .pipe(map(result => result.filter(x => x.id > 5))); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Slide 182

Slide 182 text

@Component({ selector: "my-app", template: ` {{ todo | json }} `, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todo: any; url = "https://jsonplaceholder.typicode.com/todos"; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get(this.url) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Slide 183

Slide 183 text

@Component({ selector: "my-app", template: ` {{ todo | json }} `, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todo: any; url = "https://jsonplaceholder.typicode.com/todos"; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get(this.url) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 {{ todo | json }} todo: any; @Component({ 1 selector: "my-app", 2 template: ` 3 4 `, 5 styleUrls: ["./app.component.css"] 6 }) 7 export class AppComponent implements OnInit { 8 9 url = "https://jsonplaceholder.typicode.com/todos"; 10 11 constructor(private http: HttpClient) {} 12 13 ngOnInit(): void { 14 this.http 15 .get(this.url) 16 17 18 19 20 21 } 22 } 23

Slide 184

Slide 184 text

@Component({ selector: "my-app", template: ` {{ todo | json }} `, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todo: any; url = "https://jsonplaceholder.typicode.com/todos"; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get(this.url) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 {{ todo | json }} todo: any; @Component({ 1 selector: "my-app", 2 template: ` 3 4 `, 5 styleUrls: ["./app.component.css"] 6 }) 7 export class AppComponent implements OnInit { 8 9 url = "https://jsonplaceholder.typicode.com/todos"; 10 11 constructor(private http: HttpClient) {} 12 13 ngOnInit(): void { 14 this.http 15 .get(this.url) 16 17 18 19 20 21 } 22 } 23 url = "https://jsonplaceholder.typicode.com/todos"; this.http .get(this.url) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ todo | json }} 4 `, 5 styleUrls: ["./app.component.css"] 6 }) 7 export class AppComponent implements OnInit { 8 todo: any; 9 10 11 constructor(private http: HttpClient) {} 12 13 ngOnInit(): void { 14 15 16 17 18 19 20 21 } 22 } 23

Slide 185

Slide 185 text

@Component({ selector: "my-app", template: ` {{ todo | json }} `, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todo: any; url = "https://jsonplaceholder.typicode.com/todos"; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get(this.url) .subscribe(allItems => { }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Slide 186

Slide 186 text

@Component({ selector: "my-app", template: ` {{ todo | json }} `, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todo: any; url = "https://jsonplaceholder.typicode.com/todos"; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get(this.url) .subscribe(allItems => { this.http .get(this.url + "/" + allItems[0].id) }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Slide 187

Slide 187 text

@Component({ selector: "my-app", template: ` {{ todo | json }} `, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todo: any; url = "https://jsonplaceholder.typicode.com/todos"; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get(this.url) .subscribe(allItems => { this.http .get(this.url + "/" + allItems[0].id) .subscribe(singleItem => (this.todo = singleItem)); }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Slide 188

Slide 188 text

Switchmap()

Slide 189

Slide 189 text

.subscribe(allItems => { .subscribe(singleItem => (this.todo = singleItem)); @Component({ 1 selector: "my-app", 2 template: ` 3 {{ todo | json }} 4 `, 5 styleUrls: ["./app.component.css"] 6 }) 7 export class AppComponent implements OnInit { 8 todo: any; 9 url = "https://jsonplaceholder.typicode.com/todos"; 10 11 constructor(private http: HttpClient) {} 12 13 ngOnInit(): void { 14 this.http 15 .get(this.url) 16 17 this.http 18 .get(this.url + "/" + allItems[0].id) 19 20 }); 21 } 22 } 23

Slide 190

Slide 190 text

switchMap(allItems => { return this.http.get(this.url + "/" + allItems[0].id); }) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ todo$ | async | json }} 4 `, 5 styleUrls: ["./app.component.css"] 6 }) 7 export class AppComponent implements OnInit { 8 todo$: Observable; 9 url = "https://jsonplaceholder.typicode.com/todos"; 10 11 constructor(private http: HttpClient) {} 12 13 ngOnInit(): void { 14 this.todo$ = this.http.get(this.url).pipe( 15 16 17 18 ); 19 } 20 } 21

Slide 191

Slide 191 text

switchMap(allItems => this.http.get(this.url + "/" + allItems[0].id)) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ todo$ | async | json }} 4 `, 5 styleUrls: ["./app.component.css"] 6 }) 7 export class AppComponent implements OnInit { 8 todo$: Observable; 9 url = "https://jsonplaceholder.typicode.com/todos"; 10 11 constructor(private http: HttpClient) {} 12 13 ngOnInit(): void { 14 this.todo$ = this.http.get(this.url).pipe( 15 16 ); 17 } 18 } 19

Slide 192

Slide 192 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

Slide 193

Slide 193 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{ amount }} amount: number; @Component({ 1 selector: "my-app", 2 template: ` 3 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24

Slide 194

Slide 194 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{ amount }} amount: number; @Component({ 1 selector: "my-app", 2 template: ` 3 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 url = "https://bank.com/transferMoney"; @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24

Slide 195

Slide 195 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{ amount }} amount: number; @Component({ 1 selector: "my-app", 2 template: ` 3 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 url = "https://bank.com/transferMoney"; @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 15 16 17 18 19 20 21 22 23 } 24

Slide 196

Slide 196 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{ amount }} amount: number; @Component({ 1 selector: "my-app", 2 template: ` 3 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 url = "https://bank.com/transferMoney"; @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 15 16 17 18 19 20 21 22 23 } 24 this.http .post(this.url, { transfer: 100 }) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 16 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24

Slide 197

Slide 197 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{ amount }} amount: number; @Component({ 1 selector: "my-app", 2 template: ` 3 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 url = "https://bank.com/transferMoney"; @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 15 16 17 18 19 20 21 22 23 } 24 this.http .post(this.url, { transfer: 100 }) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 16 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 .pipe(switchMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24

Slide 198

Slide 198 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{ amount }} amount: number; @Component({ 1 selector: "my-app", 2 template: ` 3 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 url = "https://bank.com/transferMoney"; @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 15 16 17 18 19 20 21 22 23 } 24 this.http .post(this.url, { transfer: 100 }) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 16 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 .pipe(switchMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 19 20 21 22 } 23 } 24

Slide 199

Slide 199 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 {{ amount }} amount: number; @Component({ 1 selector: "my-app", 2 template: ` 3 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 url = "https://bank.com/transferMoney"; @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 15 16 17 18 19 20 21 22 23 } 24 this.http .post(this.url, { transfer: 100 }) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 16 17 .pipe(switchMap(() => this.http.get("..."))) 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 .pipe(switchMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(switchMap(() => this.http.get("..."))) 18 19 20 21 22 } 23 } 24 sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(switchMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 15 16 17 18 19 20 21 22 23 } 24

Slide 200

Slide 200 text

MergeMap()

Slide 201

Slide 201 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(mergeMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

Slide 202

Slide 202 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(mergeMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 .pipe(mergeMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24

Slide 203

Slide 203 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(mergeMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 .pipe(mergeMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(mergeMap(() => this.http.get("..."))) 18 19 20 21 22 23 } 24

Slide 204

Slide 204 text

ConcatMap()

Slide 205

Slide 205 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(concatMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

Slide 206

Slide 206 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(concatMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 .pipe(concatMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24

Slide 207

Slide 207 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(concatMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 .pipe(concatMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(concatMap(() => this.http.get("..."))) 18 19 20 21 22 23 } 24

Slide 208

Slide 208 text

exhaustMap()

Slide 209

Slide 209 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(exhaustMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

Slide 210

Slide 210 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(exhaustMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 .pipe(exhaustMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24

Slide 211

Slide 211 text

@Component({ selector: "my-app", template: ` {{ amount }} Send $$$ `, styleUrls: ["./app.component.css"] }) export class AppComponent { amount: number; url = "https://bank.com/transferMoney"; constructor(private http: HttpClient) {} sendMoney(): void { this.http .post(this.url, { transfer: 100 }) .pipe(exhaustMap(() => this.http.get("..."))) .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 .pipe(exhaustMap(() => this.http.get("..."))) @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 18 .subscribe((newAmount) => { 19 this.amount = newAmount; 20 alert("transferred successfully") 21 }); 22 } 23 } 24 .subscribe((newAmount) => { this.amount = newAmount; alert("transferred successfully") }); } @Component({ 1 selector: "my-app", 2 template: ` 3 {{ amount }} 4 Send $$$ 5 `, 6 styleUrls: ["./app.component.css"] 7 }) 8 export class AppComponent { 9 amount: number; 10 url = "https://bank.com/transferMoney"; 11 12 constructor(private http: HttpClient) {} 13 14 sendMoney(): void { 15 this.http 16 .post(this.url, { transfer: 100 }) 17 .pipe(exhaustMap(() => this.http.get("..."))) 18 19 20 21 22 23 } 24

Slide 212

Slide 212 text

No content

Slide 213

Slide 213 text

Fabian Gosebrink @FabianGosebrink

Slide 214

Slide 214 text

THe End

Slide 215

Slide 215 text

Take Care!

Slide 216

Slide 216 text

https://offering.solutions/blog/articles/2021/03/08/switchmap- mergemap-concatmap-exhaustmap-explained/ https://timdeschryver.dev/blog/angular-build-once-deploy-to- multiple-environments https://offering.solutions/blog/articles/2019/10/20/ta p-map-switchmap-explained/ https://offering.solutions https://github.com/fabiangosebrink

Slide 217

Slide 217 text

No content