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"

Fb89953d3a1b1fcb862a186585c37c25?s=128

Fabian Gosebrink

April 19, 2021
Tweet

Transcript

  1. Detecting & solving pain points in applications

  2. PErsonal Experience

  3. None
  4. Feature Modules

  5. Feature Modules Libraries

  6. Feature Modules Libraries Monorepos

  7. Feature Modules Libraries Monorepos Component Relation

  8. Feature Modules Libraries Monorepos Component Relation Component Communication

  9. Feature Modules Libraries Monorepos Component Relation Component Communication Rxjs

  10. Detecting & solving pain points in applications

  11. None
  12. What is

  13. Platform

  14. Animations CDK CLI Compiler Components Dependency Injection Forms Http

  15. L18n Karma Libraries Material Protractor PWA Router Universal

  16. NgRx Cypress RxJs Language Service Lazy Loading

  17. Platform !

  18. THe Start

  19. None
  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
  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
  22. Feature Modules

  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
  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
  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
  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
  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
  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
  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
  30. None
  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
  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
  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
  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
  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
  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
  37. Encapsulation

  38. Libraries

  39. Workspace

  40. Workspace

  41. Workspace

  42. None
  43. None
  44. Workspace

  45. Workspace

  46. How to consume Libs?

  47. None
  48. None
  49. None
  50. None
  51. None
  52. None
  53. None
  54. None
  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  65. None
  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
  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
  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
  69. Abstraction

  70. How to consume Libs

  71. How to Con gure Libs?

  72. None
  73. None
  74. None
  75. None
  76. Build once Deploy Everywhere

  77. How to Con gure Libs?

  78. @NgModule({ declarations: [LibToConfigureComponent], imports: [CommonModule], exports: [LibToConfigureComponent], }) export class

    LibToConfigureModule {} 1 2 3 4 5 6
  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
  80. static con g export class LibToConfigureConfiguration { name: string; }

    1 2 3
  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
  82. static con g @NgModule({ declarations: [LibToConfigureComponent], imports: [CommonModule], exports: [LibToConfigureComponent],

    }) export class LibToConfigureModule {} 1 2 3 4 5 6
  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
  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
  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
  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
  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
  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
  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
  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
  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
  92. Dynamic con g

  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
  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
  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
  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
  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
  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
  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
  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
  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
  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
  103. Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore

    { ... } export function initApp(configurationStore: ConfigurationStore) { return () => { return new Promise<void>((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
  104. Dynamic con g @Injectable({ providedIn: 'root' }) export class ConfigurationStore

    { ... } export function initApp(configurationStore: ConfigurationStore) { return () => { return new Promise<void>((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<void>((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
  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
  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
  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
  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
  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
  110. https://github.com/FabianGosebrink/angular-library-configuration

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

  112. Eager Loaded Lazy Loaded

  113. 1. Load my con g

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

  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
  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
  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
  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
  119. Main.ts export class AppConfig { /* */ } export let

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

    APP_CONFIG = new InjectionToken<AppConfig>('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
  121. None
  122. None
  123. None
  124. None
  125. Monorepos

  126. Rethinking Libraries

  127. Library Share COde over x apps

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

  129. Feature Feature Ui Data access Utils

  130. None
  131. None
  132. Folders

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

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

    Feature
  135. Ui Feature vs.

  136. Ui Feature vs.

  137. Feature Ui vs.

  138. Container Presentational vs.

  139. Smart Dumb vs.

  140. Stateful Stateless vs.

  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<Meetup[]>; loading$: Observable<boolean>; constructor(private store: Store<any>) {} 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
  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<Meetup[]>; loading$: Observable<boolean>; constructor(private store: Store<any>) {} 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<Meetup[]>; loading$: Observable<boolean>; 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<any>) {} 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
  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<Meetup[]>; loading$: Observable<boolean>; constructor(private store: Store<any>) {} 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<Meetup[]>; loading$: Observable<boolean>; 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<any>) {} 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<any>) {} 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<Meetup[]>; 9 loading$: Observable<boolean>; 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
  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<Meetup[]>; loading$: Observable<boolean>; constructor(private store: Store<any>) {} 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<Meetup[]>; loading$: Observable<boolean>; 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<any>) {} 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<any>) {} 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<Meetup[]>; 9 loading$: Observable<boolean>; 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<Meetup[]>; 9 loading$: Observable<boolean>; 10 11 constructor(private store: Store<any>) {} 12 13 ngOnInit() { 14 15 16 17 18 this.store.dispatch(fromGroupStore.getAllMeetupsFromGroup()); 19 } 20 } 21
  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<Meetup[]>; loading$: Observable<boolean>; constructor(private store: Store<any>) {} 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<Meetup[]>; loading$: Observable<boolean>; 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<any>) {} 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<any>) {} 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<Meetup[]>; 9 loading$: Observable<boolean>; 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<Meetup[]>; 9 loading$: Observable<boolean>; 10 11 constructor(private store: Store<any>) {} 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<Meetup[]>; 9 loading$: Observable<boolean>; 10 11 constructor(private store: Store<any>) {} 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
  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<Meetup[]>; loading$: Observable<boolean>; constructor(private store: Store<any>) {} 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<Meetup[]>; loading$: Observable<boolean>; 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<any>) {} 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<any>) {} 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<Meetup[]>; 9 loading$: Observable<boolean>; 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<Meetup[]>; 9 loading$: Observable<boolean>; 10 11 constructor(private store: Store<any>) {} 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<Meetup[]>; 9 loading$: Observable<boolean>; 10 11 constructor(private store: Store<any>) {} 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<Meetup[]>; loading$: Observable<boolean>; constructor(private store: Store<any>) {} 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
  147. Stateful <div class="container"> <h1 class="mt-3">All Gatherings of the Group</h1> <mat-progress-bar

    *ngIf="loading$ | async; else list" mode="indeterminate" ></mat-progress-bar> <ng-template #list> <workspace-meetup-list [items]="items$ | async"> </workspace-meetup-list> </ng-template> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13
  148. Stateful <div class="container"> <h1 class="mt-3">All Gatherings of the Group</h1> <mat-progress-bar

    *ngIf="loading$ | async; else list" mode="indeterminate" ></mat-progress-bar> <ng-template #list> <workspace-meetup-list [items]="items$ | async"> </workspace-meetup-list> </ng-template> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 <workspace-meetup-list [items]="items$ | async"> </workspace-meetup-list> <div class="container"> 1 <h1 class="mt-3">All Gatherings of the Group</h1> 2 3 <mat-progress-bar 4 *ngIf="loading$ | async; else list" 5 mode="indeterminate" 6 ></mat-progress-bar> 7 8 <ng-template #list> 9 10 11 </ng-template> 12 </div> 13
  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
  150. Stateless <div class="mb-20"> <ng-template #noItems> No items found... </ng-template> <div

    *ngIf="items?.length > 0; else noItems"> <ul> <li *ngFor="let item of items"> {{ item.name }} </li> </ul> </div> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  151. Stateless <div class="mb-20"> <ng-template #noItems> No items found... </ng-template> <div

    *ngIf="items?.length > 0; else noItems"> <workspace-meetup-item *ngFor="let item of items" [item]="item" > </workspace-meetup-item> </div> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13
  152. Stateless <div class="mb-20"> <ng-template #noItems> No items found... </ng-template> <div

    *ngIf="items?.length > 0; else noItems"> <workspace-meetup-item *ngFor="let item of items" [item]="item" (itemClicked)="navigateToItem($event)" > </workspace-meetup-item> </div> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  153. Stateless <div class="mb-20"> <ng-template #noItems> No items found... </ng-template> <div

    *ngIf="items?.length > 0; else noItems"> <workspace-meetup-item *ngFor="let item of items" [item]="item" (itemClicked)="bubbleNavigateEvent($event)" > </workspace-meetup-item> </div> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  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
  155. Stateful Stateless [ ... ] ( ... )

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

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

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

    ... ] ( ... ) Service
  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
  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
  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
  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
  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
  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
  165. RxJs

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

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

    angular course, you need an rxjs course" Colleague - some time ago
  168. Tap Map SwitchMap MergeMap ConcatMap ExhaustMap

  169. Keep the stream

  170. .Subscribe() Does not keep the stream

  171. @Component({ selector: "my-app", template: `{{ todos | json }}` })

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

    export class AppComponent implements OnInit { todos: any[]; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get<any[]>("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<any[]>("https://...") 12 .subscribe(result => { 13 this.todos = result; 14 }); 15 } 16 } 17
  173. @Component({ selector: "my-app", template: `{{ todos | json }}` })

    export class AppComponent implements OnInit { todos: any[]; constructor(private http: HttpClient) {} ngOnInit(): void { this.http .get<any[]>("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<any[]>("https://...") 12 .subscribe(result => { 13 this.todos = result; 14 }); 15 } 16 } 17 ngOnInit(): void { this.http .get<any[]>("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
  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<any[]>("https://...") 12 13 } 14 } 15
  175. @Component({ selector: "my-app", template: `{{ todos$ | async | json

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

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

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

    }}`, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todos$: Observable<number>; constructor(private http: HttpClient) {} ngOnInit(): void { this.todos$ = this.http.get<any[]>("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<number>; @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<any[]>("https://...") 12 .pipe(map(result => result.length)); 13 } 14 } 15
  180. @Component({ selector: "my-app", template: `{{ todos$ | async | json

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

    }}`, styleUrls: ["./app.component.css"] }) export class AppComponent implements OnInit { todos$: Observable<any[]>; constructor(private http: HttpClient) {} ngOnInit(): void { this.todos$ = this.http.get<any[]>("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
  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<any[]>(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
  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<any[]>(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<any[]>(this.url) 16 17 18 19 20 21 } 22 } 23
  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<any[]>(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<any[]>(this.url) 16 17 18 19 20 21 } 22 } 23 url = "https://jsonplaceholder.typicode.com/todos"; this.http .get<any[]>(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
  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<any[]>(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
  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<any[]>(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
  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<any[]>(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
  188. Switchmap()

  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<any[]>(this.url) 16 17 this.http 18 .get(this.url + "/" + allItems[0].id) 19 20 }); 21 } 22 } 23
  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<any>; 9 url = "https://jsonplaceholder.typicode.com/todos"; 10 11 constructor(private http: HttpClient) {} 12 13 ngOnInit(): void { 14 this.todo$ = this.http.get<any[]>(this.url).pipe( 15 16 17 18 ); 19 } 20 } 21
  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<any>; 9 url = "https://jsonplaceholder.typicode.com/todos"; 10 11 constructor(private http: HttpClient) {} 12 13 ngOnInit(): void { 14 this.todo$ = this.http.get<any[]>(this.url).pipe( 15 16 ); 17 } 18 } 19
  192. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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
  193. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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
  194. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  195. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  196. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  197. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  198. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  199. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  200. MergeMap()

  201. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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
  202. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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
  203. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  204. ConcatMap()

  205. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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
  206. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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
  207. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  208. exhaustMap()

  209. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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
  210. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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
  211. @Component({ selector: "my-app", template: ` {{ amount }} <button (click)="sendMoney()">Send

    $$$</button> `, 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 <button (click)="sendMoney()">Send $$$</button> 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 <button (click)="sendMoney()">Send $$$</button> 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
  212. None
  213. Fabian Gosebrink @FabianGosebrink

  214. THe End

  215. Take Care!

  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

  217. None