简体   繁体   English

角度加载本地文件,然后进行 http 调用以返回 observables

[英]angular load local file then make http calls to return observables

I am new to Angular, JS, and observables.我是 Angular、JS 和 observables 的新手。 I have a typescript class called DataService.我有一个名为 DataService 的打字稿类。 I want it to load a list of URLs from a JSON formatted local file, and then have some way to call those URLs (to a handful of REST APIs) and return observables.我希望它从一个 JSON 格式的本地文件加载一个 URL 列表,然后有一些方法来调用这些 URL(到少数 REST API)并返回可观察值。 The problem I am having is my code is not waiting for the config file to be loaded before the REST API functions get called.我遇到的问题是我的代码在调用 REST API 函数之前没有等待加载配置文件。

I thought I could have the DataService constructor load the configuration file, and then have unique functions for each REST API call, but that isn't working我以为我可以让 DataService 构造函数加载配置文件,然后为每个 REST API 调用提供独特的函数,但这不起作用

my code:我的代码:

export class DataService {

  configFile

  constructor(private http: HttpClient) {
    this.http.get('/assets/restApiUrlListConfig.json').subscribe(config => {
      this.configFile = config;
    });
  }

  getUrlFromConfigFile(name: string): string {
    ...
      this returns the URL from the config file
    ...
  }

  getUrlAData(): Observable {
    return this.http.get( getUrlFromConfigFile('A') )
  }

}

My other components have code like this:我的其他组件有这样的代码:

export class SomeComponent implements OnInit {

someComponentAData

constructor(private data: DataService) { }

ngOnInit() {
    this.data.getUrlAData().subscribe(
        data => {
            this.someComponentAData = data
        }
    )
}

I am getting an error that the observable returned from the dataservice is undefined.我收到一个错误,指出从数据服务返回的可观察对象未定义。 Which I believe is because the constructor hasn't finished loading the config file, which I think is why the function getUrlAData isn't returning anything.我相信这是因为构造函数尚未完成加载配置文件,我认为这就是函数 getUrlAData 没有返回任何内容的原因。

I feel like I'm not correctly handling these async calls, but I'm at a loss for how to tell my code to :我觉得我没有正确处理这些异步调用,但我不知道如何告诉我的代码:

  1. create the data service object创建数据服务对象
  2. load the data file before anything else can be done在做任何其他事情之前加载数据文件
  3. allow the other functions to be called asyncronously AFTER the config file is loaded允许在加载配置文件后异步调用其他函数

Angular CLI: 6.2.3角 CLI:6.2.3
Node: 8.12.0节点:8.12.0
OS: win32 x64操作系统:win32 x64
Angular: 6.1.8角度:6.1.8

Edit 1: attempting to implement suggested solution编辑 1:尝试实施建议的解决方案

My DataService我的数据服务

  configFile
  configObservable: Observable<any>;
  someSubscribeObj

  constructor(private http: HttpClient) {

    this.someSubscribeObj = this.http.get('/assets/restApiUrlListConfig.json').subscribe(config => {
      this.someSubscribeObj = undefined;
      this.configFile = config;
    });

  }

  getObsFromConfigFile(name: string): Observable<any> {
    //...
    if (this.configFile != undefined) {
      console.log('this.restApiUrlListConfig[name]',this.configFile[name])
      return of(this.configFile[name])
    }
    else
      return of(this.someSubscribeObj.pipe(map(c => c[name]))) 
      //this.configObservable
    //...
  }


  getUrlAData(): Observable<any> {
    return this.getObsFromConfigFile('A').pipe(mergeMap(url => this.http.get(url)))
  }

My other component:我的另一个组件:

  constructor( private data: DataService ) { }

  ngOnInit() {

    //this.data.loggedIn.pipe((p) => p);

    this.data.getUrlAData().subscribe(
      data => {
        this.urlAData = data
      }
    )
}

I was unable to store the "subscribe" into the observable, so I created a generic Any type varable, but at runtime I get a problem with the pipe command:我无法将“订阅”存储到 observable 中,所以我创建了一个通用的 Any 类型变量,但在运行时我遇到了管道命令的问题:

TypeError: this.someSubscribeObj.pipe is not a function at DataService.push../src/app/services/data.service.ts.DataService.getObsFromConfigFile (data.service.ts:67) at DataService.push../src/app/services/data.service.ts.DataService.getUrlAData (data.service.ts:74) TypeError: this.someSubscribeObj.pipe 不是 DataService.push../src/app/services/data.service.ts.DataService.getObsFromConfigFile (data.service.ts:67) 上的函数,位于 DataService.push../src /app/services/data.service.ts.DataService.getUrlAData (data.service.ts:74)

Edit 2: the unfortunate workaround编辑 2:不幸的解决方法

I am currently using two nested subscriptions to get the job done basically我目前正在使用两个嵌套订阅来基本上完成工作

http.get(config_file_url).subscribe( 
config => { 
http.get( config['A'] ).subscribe( adata => { do things }; 
http.get config['B'].subscribe( bdata => {do things };
}
)

I feel like I should be able to use a mergeMap of some sort, but I couldn't get them to work as I thought they would.我觉得我应该能够使用某种形式的 mergeMap,但我无法让它们像我想象的那样工作。

You need to wait on that async call, I would use a flatmap to get the value out of an observable.您需要等待该异步调用,我将使用平面图从可观察对象中获取值。

export class DataService {

  configFile
  configObservable: Observable<any>;

  constructor(private http: HttpClient) {
    this.configObservable = this.http.get('/assets/restApiUrlListConfig.json').pipe(
      map(config => {
        this.configObservable = undefined;
        this.configFile = config;
        return configFile;
      })
      );
  }

  getUrlFromConfigFile(name: string): Observable<string> {
    ...
      return of(configFile[name]) if configFile is set else return configObservable.pipe(map(c => c[name]));
    ...
  }

  getUrlAData(): Observable<string> {
    return this.getUrlFromConfigFile('A').pipe(map(url => this.http.get(url)))
  }

}

Basically you want to store the observable and keep using it till it completes, after it completes you can just wrap the config in an observable.基本上你想存储 observable 并继续使用它直到它完成,完成后你可以将配置包装在一个 observable 中。 The reason for wrapping it is to make the interface consistent, otherwise you have to have an if before every get.包装它的原因是为了让接口保持一致,否则每次get之前都要有一个if。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM