如何通过GET请求填充服务内部的静态数组?

时间:2019-06-04 12:24:55

标签: javascript angular typescript angular-services angular-components

我想做的(我认为)很简单。我正在构建一个Web应用程序,我想用来自远程JSON文件(GET请求)的相同数据填充一些select元素。我创建了一个 service ,我想在其中填充一个静态数组,然后从所需的任何组件中调用它。我想我错过了至关重要的事情。
这里是一些代码:
fetchData.service.ts

export interface Creditor {
  id: number;
  name: string;
}

@Injectable()
export class FetchDataService {

    creditorsStaticArray: Creditor[] = [];

    getCreditorsFromAPI() {
        this.http.get<Creditor[]>(this.creditorsUrl)
            .subscribe(
              items => {
                this.creditorsStaticArray = items;
              }
            );
      }

    getCreds() {
        return this.creditorsStaticArray;
    }
}

application-details.component.ts (组件之一)

export class ApplicationDetailsComponent implements OnInit {

    loadedCreditors: Creditor[] = [];

    constructor(private fetchDataService: FetchDataService) { }

    ngOnInit() {
        this.fetchDataService.getCreditorsFromAPI();
        this.loadedCreditors = this.fetchDataService.getCreds();
    }

}

我的解决方案基于this answer

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:4)

您的静态数组不能超出您的服务范围。但是,您也无法在static中真正拥有class scope

由于默认情况下Angular中的servicessingletons,因此您可以通过执行以下操作来实现目标目标:

@Injectable()
export class FetchDataService {

    creditorsStaticArray: Creditor[] = [];

    getCreditorsFromAPI() {
        this.http.get<Creditor[]>(this.creditorsUrl)
            .subscribe(
              items => {
                this.creditorsStaticArray = items;
              }
            );
      }

    getCreds() {
        return this.creditorsStaticArray;
    }
}

正如您已经提到的this.creditorsStaticArray,这将立即起作用。您可能需要考虑将其重命名为creditorsCache或类似名称,并阻止它从服务外部直接访问(通过使其成为private),因为它不再static。但是除了命名约定和访问限制器之外,您还可以实现所需的目标。


现在,我将在底部添加一些最佳做法,以供将来参考。

您正在订阅服务,而不是“明确”管理订阅。这不一定很糟糕,因为默认的HttpClient将在第一个结果后完成,但是可能值得添加一个.pipe(first()).pipe(take(1))firsttake(1)的别名)。这样,如果您的API或检索数据的方式发生了变化,则有一个明确的提醒,该Observable将采用1个值(整个数组)并自行完成,并将结果作为副作用保存到变量中。

您可能要考虑的不是服务内部的subscribing,而是将整个Observable返回给您的组件,以便其传递并确定订阅时间。您仍然可以通过将变量的状态放在

中来保存状态
.pipe(
   tap(data => { this.creditorsCache = data })
)

您或您的组件(或使用AsyncPipe的HTML)进行订阅时;它将其存储在其缓存中,并且您可以自动处理新收到的结果。

在上面的示例中,您仍然可以依靠caching机制来通过每次将缓存的数据作为Observable返回而不每次都击中服务器。幸运的是,RxJS提供了很多Observables的创建方式,这应该不会太复杂!

一个简单的例子:


getCreditorsFromAPI(): Observable<Creditor[]> {
  return this.http.get<Creditor[]>(this.creditorsUrl)
            .pipe(
                tap(data => this.creditorsCache = data)
             )
  );
}

getCreds(): Observable<Creditor[]> {
    // You could also use this to invalidate your cache after 10 minutes!
    if(this.creditorsCache.length > 0) {
        return of(this.creditorsCache)
    }

    // Because I set the return type of this function, you will need to return a valid Observable. This makes your code predictable!
    return this.getCreditorsFromAPI() // This will recreate your cache cause of the tap()!
}

在上面的示例中,您只能调用service.getCreds()并在组件中管理预订。每次您将可观察对象重新分配给this.service.getCreds()时,它将自动为您缓存。

值得深思!我不会说有一种完美的做事方式,而且肯定有更多的方式通往具有象征意义的罗马。但是我刚才所描述的肯定是Reactive多一点,这是Angular内部很多方面所依赖的。

答案 1 :(得分:1)

从您的服务中返回可观察到的信息:

@Injectable()
export class FetchDataService {

    creditorsStaticArray: Creditor[] = [];

    getCreditorsFromAPI() {
        return this.http.get<Creditor[]>(this.creditorsUrl);
      }
}

在您的组件中:

 loadedCreditors: Creditor[] = [];

ngOnInit() {
    this.fetchDataService.getCreditorsFromAPI()
        .subscribe(res => this.loadedCreditors = res)

}