angular multiple APP_INITIALIZER that depend on each other

蹲街弑〆低调 提交于 2020-12-08 07:58:11

问题


Background: I need to perform couple of initial checks during the application start up (1) read angular app config from ./assets/config.json file and get the API end point from there, (2) make an API call to end point retrieved in first step and load some settings from back end.

Goal: be able to initialize two services using APP_INITIALIZER (say A & B), where B has a dependency on A. check out this stackblitz to see the problem

Things I've tried: If second part (being able to make an API request to the back-end) was not in the picture, then I managed to use angular APP_INITIALIZER to get things done, I then searched for some articles and found this one Managing dependencies among App Initializers in Angular, which has 3 approaches listed, 3rd one being the recommended one (as it is easy to maintain), but I don't really understand all of it, I believe author has not included full code implementation of each approach (I do get that it's authors call whether to provide code samples or not, and I might be wrong). I would really appreciate if anyone with experience could share their knowledge wrt the same.

PS: I haven't added any code in here as I am not really confident if what I have tried is sensible or not, but happy to add some code.

Stackblitz1 (single APP_INITIALIZER) - https://stackblitz.com/edit/angular-puaw7a

[The Problem] Stackblitz2 (multiple APP_INITIALIZER) - https://stackblitz.com/edit/angular-7uqijv


回答1:


just use

useFactory: (appConfigSvc: ConfigService,settingsService:SettingsService) => {
        return () => {
          return appConfigSvc.loadConfig().then(()=>{
            return settingsService.loadConfig()
          });
        };
      }

See your forked code in stackblitz




回答2:


I don't think you actually need an initializer in your case. You just have a value that other services depend on. The problem in your code is that you have an async value and try to expose it as a sync value.

I think your problems would be solved if you would just expose the config as an Observable and "await" it where it's needed. The benefits are that the application loads as much as it can until the config requests are done.

For example the shareReplay(1) operator will keep in memory the item and will defer the HTTP request until it's actually needed:

export class ConfigService {

  configData$ = this.httpClient.get<{config1:string}>('./assets/config.json').pipe(shareReplay(1));

  constructor(private httpClient: HttpClient) { }
}

Now your 2nd service can await the configData from the 1st service. Or just transform it via observable piping and expose it further as an observable to defer everything until it's actually needed.

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

  settingsData$ = this.configService.configData$.pipe(
    map(c => c.config1 + '...and config service dependent action'),
    shareReplay(1), // also keep the value in memory maybe?
  );

  constructor(
    private httpClient: HttpClient,
    private configService: ConfigService
    ) { }
}
export class HelloComponent implements OnInit {

  @Input() name: string;

  dataFromConfigSvc: Observable<string>;
  constructor(private configService: ConfigService) { }

  ngOnInit() {
    // you could either use async pipe in the template or subscribe here and get the value
    this.dataFromConfigSvc = this.configService.configData$.pipe(map(c => c.config1));
  }

}


来源:https://stackoverflow.com/questions/57585082/angular-multiple-app-initializer-that-depend-on-each-other

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!