Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Detecting and solving pain points in Angular Applications

Detecting and solving pain points in Angular Applications

Starting any Angular Project is easy. AngularCLI provides a great user API, scaffolding is powerful, and the first pages, components are easy to create. But when the application grows, you and your team can run into a lot of problems when developing, architecting and maintaining a single-page application.

Suddenly the architecture gets unmaintainable, dividing the application into logical parts is a challenge and implementing asynchronous operations is hard. Handling the application state and including third party libraries in a proper manner becomes a real challenge. In this talk Fabian Gosebrink shows typical tasks, problems and solutions for mistakes which can be found in Angular applications. We will look at different problems, understand the challenge and develop a solution for common mistakes in Angular solutions so that your next project doesn’t end with "If only somebody told me this before I started my Angular SPA"

Fabian Gosebrink

April 19, 2021
Tweet

More Decks by Fabian Gosebrink

Other Decks in Technology

Transcript

  1. Detecting & solving
    pain points in
    applications

    View Slide

  2. PErsonal
    Experience

    View Slide

  3. View Slide

  4. Feature Modules

    View Slide

  5. Feature Modules
    Libraries

    View Slide

  6. Feature Modules
    Libraries
    Monorepos

    View Slide

  7. Feature Modules
    Libraries
    Monorepos
    Component Relation

    View Slide

  8. Feature Modules
    Libraries
    Monorepos
    Component Relation
    Component Communication

    View Slide

  9. Feature Modules
    Libraries
    Monorepos
    Component Relation
    Component Communication
    Rxjs

    View Slide

  10. Detecting & solving
    pain points in
    applications

    View Slide

  11. View Slide

  12. What is

    View Slide

  13. Platform

    View Slide

  14. Animations CDK CLI Compiler
    Components Dependency
    Injection
    Forms Http

    View Slide

  15. L18n Karma Libraries Material
    Protractor PWA Router Universal

    View Slide

  16. NgRx Cypress RxJs Language
    Service
    Lazy Loading

    View Slide

  17. Platform !

    View Slide

  18. THe Start

    View Slide

  19. View Slide

  20. 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

    View Slide

  21. 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

    View Slide

  22. Feature
    Modules

    View Slide

  23. 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

    View Slide

  24. 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

    View Slide

  25. 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

    View Slide

  26. 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

    View Slide

  27. 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

    View Slide

  28. 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

    View Slide

  29. 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

    View Slide

  30. View Slide

  31. 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

    View Slide

  32. 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

    View Slide

  33. 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

    View Slide

  34. 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

    View Slide

  35. 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

    View Slide

  36. 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

    View Slide

  37. Encapsulation

    View Slide

  38. Libraries

    View Slide

  39. Workspace

    View Slide

  40. Workspace

    View Slide

  41. Workspace

    View Slide

  42. View Slide

  43. View Slide

  44. Workspace

    View Slide

  45. Workspace

    View Slide

  46. How to
    consume
    Libs?

    View Slide

  47. View Slide

  48. View Slide

  49. View Slide

  50. View Slide

  51. View Slide

  52. View Slide

  53. View Slide

  54. View Slide

  55. 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

    View Slide

  56. 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

    View Slide

  57. 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

    View Slide

  58. 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

    View Slide

  59. 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

    View Slide

  60. 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

    View Slide

  61. 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

    View Slide

  62. 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

    View Slide

  63. 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

    View Slide

  64. 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

    View Slide

  65. View Slide

  66. 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

    View Slide

  67. 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

    View Slide

  68. 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

    View Slide

  69. Abstraction

    View Slide

  70. How to
    consume
    Libs

    View Slide

  71. How to
    Con gure
    Libs?

    View Slide

  72. View Slide

  73. View Slide

  74. View Slide

  75. View Slide

  76. Build once
    Deploy
    Everywhere

    View Slide

  77. How to
    Con gure
    Libs?

    View Slide

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

    View Slide

  79. @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

    View Slide

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

    View Slide

  81. 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

    View Slide

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

    View Slide

  83. 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

    View Slide

  84. 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

    View Slide

  85. 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

    View Slide

  86. 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

    View Slide

  87. 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

    View Slide

  88. 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

    View Slide

  89. 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

    View Slide

  90. 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

    View Slide

  91. 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

    View Slide

  92. Dynamic con g

    View Slide

  93. 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

    View Slide

  94. 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

    View Slide

  95. 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

    View Slide

  96. 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

    View Slide

  97. 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

    View Slide

  98. 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

    View Slide

  99. 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

    View Slide

  100. 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

    View Slide

  101. 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

    View Slide

  102. 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

    View Slide

  103. 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

    View Slide

  104. 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

    View Slide

  105. 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

    View Slide

  106. 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

    View Slide

  107. 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

    View Slide

  108. 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

    View Slide

  109. 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

    View Slide

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

    View Slide

  111. https://bit.ly/32lPE4a

    View Slide

  112. Eager Loaded
    Lazy Loaded

    View Slide

  113. 1. Load my con g

    View Slide

  114. 1. Load my con g
    2. start my app

    View Slide

  115. 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

    View Slide

  116. 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

    View Slide

  117. 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

    View Slide

  118. 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

    View Slide

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

    View Slide

  120. 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

    View Slide

  121. View Slide

  122. View Slide

  123. View Slide

  124. View Slide

  125. Monorepos

    View Slide

  126. Rethinking
    Libraries

    View Slide

  127. Library
    Share COde over x apps

    View Slide

  128. Library
    Share COde over x apps
    parts of a feature!

    View Slide

  129. Feature
    Feature
    Ui
    Data access
    Utils

    View Slide

  130. View Slide

  131. View Slide

  132. Folders

    View Slide

  133. Lib: Api
    Lib: Data
    Lib: Ui
    Lib: Util
    Lib: Feature

    View Slide

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

    View Slide

  135. Ui
    Feature
    vs.

    View Slide

  136. Ui
    Feature
    vs.

    View Slide

  137. Feature
    Ui
    vs.

    View Slide

  138. Container
    Presentational
    vs.

    View Slide

  139. Smart
    Dumb
    vs.

    View Slide

  140. Stateful
    Stateless
    vs.

    View Slide

  141. 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

    View Slide

  142. 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

    View Slide

  143. 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

    View Slide

  144. 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

    View Slide

  145. 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

    View Slide

  146. 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

    View Slide

  147. Stateful

    All Gatherings of the Group
    *ngIf="loading$ | async; else list"
    mode="indeterminate"
    >





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

    View Slide

  148. Stateful

    All Gatherings of the Group
    *ngIf="loading$ | async; else list"
    mode="indeterminate"
    >





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



    1
    All Gatherings of the Group
    2
    3
    4
    *ngIf="loading$ | async; else list"
    5
    mode="indeterminate"
    6
    >
    7
    8

    9
    10
    11

    12

    13

    View Slide

  149. 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

    View Slide

  150. Stateless


    No items found...

    0; else noItems">


    {{ item.name }}




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

    View Slide

  151. Stateless


    No items found...

    0; else noItems">
    *ngFor="let item of items"
    [item]="item"
    >



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

    View Slide

  152. Stateless


    No items found...

    0; else noItems">
    *ngFor="let item of items"
    [item]="item"
    (itemClicked)="navigateToItem($event)"
    >



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

    View Slide

  153. Stateless


    No items found...

    0; else noItems">
    *ngFor="let item of items"
    [item]="item"
    (itemClicked)="bubbleNavigateEvent($event)"
    >



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

    View Slide

  154. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  159. 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

    View Slide

  160. 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

    View Slide

  161. 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

    View Slide

  162. 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

    View Slide

  163. 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

    View Slide

  164. 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

    View Slide

  165. RxJs

    View Slide

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

    View Slide

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

    View Slide

  168. Tap
    Map
    SwitchMap
    MergeMap
    ConcatMap
    ExhaustMap

    View Slide

  169. Keep the
    stream

    View Slide

  170. .Subscribe()
    Does not keep
    the stream

    View Slide

  171. @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

    View Slide

  172. @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

    View Slide

  173. @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

    View Slide

  174. .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

    View Slide

  175. @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

    View Slide

  176. @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

    View Slide

  177. 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

    View Slide

  178. @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

    View Slide

  179. @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

    View Slide

  180. @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

    View Slide

  181. @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

    View Slide

  182. @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

    View Slide

  183. @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

    View Slide

  184. @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

    View Slide

  185. @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

    View Slide

  186. @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

    View Slide

  187. @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

    View Slide

  188. Switchmap()

    View Slide

  189. .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

    View Slide

  190. 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

    View Slide

  191. 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

    View Slide

  192. @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

    View Slide

  193. @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

    View Slide

  194. @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

    View Slide

  195. @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

    View Slide

  196. @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

    View Slide

  197. @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

    View Slide

  198. @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

    View Slide

  199. @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

    View Slide

  200. MergeMap()

    View Slide

  201. @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

    View Slide

  202. @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

    View Slide

  203. @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

    View Slide

  204. ConcatMap()

    View Slide

  205. @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

    View Slide

  206. @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

    View Slide

  207. @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

    View Slide

  208. exhaustMap()

    View Slide

  209. @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

    View Slide

  210. @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

    View Slide

  211. @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

    View Slide

  212. View Slide

  213. Fabian
    Gosebrink
    @FabianGosebrink

    View Slide

  214. THe End

    View Slide

  215. Take Care!

    View Slide

  216. 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

    View Slide

  217. View Slide