【问题标题】:Class variable doesn't persist outside of subscribe in Angular 8类变量不会在 Angular 8 中的订阅之外持续存在
【发布时间】:2020-01-30 19:06:31
【问题描述】:

类变量counties 不保留在fetchCounties() 的subscribe 方法中分配的值。记录临时变量数据会返回一个很好的县列表,订阅内部的 this.counties 也是如此,但是一旦我尝试在订阅之外访问它,它就会变得未定义。来自 Java 背景并且是 Angular/Typescript 的新手,这对我来说毫无意义......

public counties: ICounty[] = [];  

public getCounties(): ICounty[] {
        this.fetchCounties().subscribe(data =>{
          console.log("data");
          console.log(data);//logs correctly
          this.counties = data;
          console.log("counties inside subscribe " );
          console.log(this.counties);//logs correctly
        });
        console.log("counties outside of subscribe " );
        console.log(this.counties);//logs incorrectly (empty) >:0
        return this.removeInvalidCounties(this.counties); //passes empty counties list...
}

【问题讨论】:

  • susbscribe 异步运行,它在fetchCounties 发出时运行。
  • Java没有异步功能吗?我不是专家,但我认为他们在那里的工作方式类似。
  • 可能是最新的 java 版本,但我习惯于 Java 7/8 和旧版应用程序。我只是觉得无法将类变量分配给我需要的任何值非常奇怪。
  • 问题不在于代码没有在订阅中运行,问题在于 this.counties 的值是在订阅中设置的,但直到为时已晚才知道这一点。我想这是一个状态问题。所以我的理解是,即使订阅没有完成,调用代码也会继续执行?如何在执行其他代码之前强制订阅完成?

标签: angular typescript


【解决方案1】:

要解决此问题,您可以:

  public getCounties(): Observable<ICounty[]> {
    return this.fetchCounties().pipe(
       map(counties => {
         // write your logic here in what makes a county valid, I will say it has to have a name
        return counties.filter(county => county.name);
      }),
    );
  }

然后你可以把它当作一个可观察对象来消费:

this.countiesService.getCounties().subscribe(counties => {...});

然后在你的组件中你可以这样做:

counties: ICounty[];

constructor(private countiesService: CountiesService) {}

ngOnInit() {
  this.countiesService.fetchCounties().subscribe(counties => this.counties = counties);
}

html 可以是:

<li *ngFor="let county of counties">{{ county }}</li>

或者更好的是,使用异步管道在视图被销毁时自动取消订阅:

counties$ = this.countiesService.fetchCounties();

然后在 HTML 中:

<li *ngFor="let county of counties$ | async">{{ county }}</li>

================ 关于您的问题,您如何才能等待订阅完成后再继续,您可以将其转换为承诺,尽管我不推荐这种方式。

public counties: ICounty[] = [];

// Typescript might complain here, saying an async function has to return a promise
public async getCounties() { 
  this.counties = await this.fetchCounties().pipe(take(1)).toPromise();
  return this.removeInvalidCounties(this.counties);
}

【讨论】:

  • 问题是我想在 CountyService 类中完成所有县列表的检索和过滤,并简单地公开一个 getCounties() 方法,该方法可用于在任何地方分配组件中的变量到一个有效县的列表,这样我就可以从客户使用中抽象出所有细节。
  • 你能解释一下为什么不使用 promise 方法吗?
  • 一个原因是 TypeScript 会抱怨异步函数必须返回一个承诺。就个人而言,我不喜欢将 Promise 与 observables 混合在一起。我喜欢只使用 Observables,因为它们更具反应性。承诺是一成不变的。在这种情况下,它是一个 HTTP 调用,所以没有什么区别,但我喜欢留在可观察的世界中。
【解决方案2】:

那是因为您试图在异步调用完成之前访问数组 (fetchCounties)。

public counties: ICounty[] = [];  

public getCounties(): ICounty[] {
  // step 1
  this.fetchCounties().subscribe(data =>{
  // step 3 because is asynchronous and it depends on the time of the call required.
  });
  // step 2
  return this.removeInvalidCounties(this.counties);
}

我不知道你想做什么。但可能,您应该在订阅中执行 removeInvalidCounties。

更新:如果您尝试过滤您尝试使用的国家/地区。你可以这样做。

public getCounties(): ICounty[] {
  this.fetchCounties()
  .pipe(map(countries => this.removeInvalidCounties(counties)))
  .subscribe(data =>{
    this.counties = data ;
  });
}

【讨论】:

    猜你喜欢
    • 2020-05-18
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 2020-12-14
    • 1970-01-01
    • 2018-11-30
    • 2016-04-12
    • 2023-04-05
    相关资源
    最近更新 更多