无法将订阅的可观察对象作为字符串放入集合中

Cannot put subscribed observable into collection as a string

我是 typescript 和 javascript 的新手,我真的很难搞清楚集合和文件 io 是如何工作的。我正在尝试从 json 文件中获取数据,尽管当我将其放入集合中时该集合没有数据,但我成功了。

代码如下:

为我服务class:

  private configuration = "../../assets/Configurations/testConfiguration.json";

  constructor(private http: HttpClient) {}

  getBlogs(blog: string): Observable<IBlogPost[]> {
    return this.http.get<IBlogPost[]>(blog);
  }

  getConfigurations() {
    var configurationsData = [];
    this.http.get(this.configuration).subscribe(data => {
      configurationsData.push(data);
      console.log(data);
      // This will work and will print all the paths
    });

    //This will not work and will not print them, like if the collection is empty
    configurationsData.forEach(x => console.log(x));

    return configurationsData;
  }

我在哪里获得我的服务 class 注入:

blogs: IBlogPost[] = [];

  private blogsPaths: string[] = [];

  errorMessage = "";

  constructor(private appUtilityService: AppUtilityServices) {}

  ngOnInit() {
    //This will not work, blogsPaths will not received the full collection as it should
    this.blogsPaths = this.appUtilityService.getConfigurations();



    this.blogsPaths.forEach(blogPath =>
      this.appUtilityService.getBlogs(blogPath).subscribe(
        b =>
          b.forEach(blog => {
            this.blogs.push(blog);
          }),
        error => (this.errorMessage = <any>error)
      )
    );
  }

testConfiguration.json:

[
  "../../assets/BlogPosts/testBlog1.json",
  "../../assets/BlogPosts/testBlog2.json"
]

如果您包含有关集合如何在 javascript 中工作以及如何正确 return 它们的好教程,则可获赠

getConfigurations 中,您正在调用异步 http 请求。所以这很正常, configurationsDatasubscribe 方法之外是空的。

在这里,我使用强大的RxJS来简化代码并避免使用 Array.push 和嵌套 subscribe().

1) 获取数据的基本异步服务方法

所以 getConfigurations 应该 return 一个 Observable:

getConfigurations(): Observable<string[]> {
  return this.http.get<string[]>(this.configuration);
}

而且 getBlogs 应该 return 一个 Observable:

getBlogs(blogsPath: string): Observable<BlogPost[]> {
  return this.http.get<BlogPost[]>(blogsPath);
}

在这里,为了尊重Angular最佳实践,我删除了每个界面开头的I,所以BlogPost.

2) 这就是RxJS的神奇之处

然后,您的服务中有另一种方法可以检索 Observable 篇博文,它应该如下所示:

getBlogPosts(): Observable<BlogPost[]> {
  return this.getConfigurations().pipe(
    mergeAll(),
    concatMap(blogsPath => this.getBlogs(blogsPath)),
    concatAll(),
    toArray()
  )
}

这意味着,检索博客路径的所有集合,对于每个路径数组,对于每个路径,获取博客帖子,然后 return 所有帖子的唯一数组。

最后,在您的组件中,您通过订阅调用 getBlogPosts

ngOnInit() {
  this.service.getBlogPosts().subscribe(blogs => {
    ...do something with your blogs array.
  });
}

或者在模板中使用 async 管道更好:

.ts 文件:

blogs$: Observable<BlogPost[]>;
...
this.blogs$ = this.appService.getBlogPosts();

.html 文件:

<ul *ngIf="blogs$ | async as blogs">
    <li *ngFor="let blog of blogs">
        #{{ blog.id }} - {{ blog.title }}
    </li>
</ul>

在 Stackbliz 上查看我的 full demonstration of this RxJS alternative

推荐阅读 medium from Tomas Trajan

原来是这样,是的真的...

这里我做得很好:

初始化时:

this.appUtilityService.getConfigurations().subscribe(
  b =>
    b.forEach(x => {
      this.appUtilityService.getBlogs(x).subscribe(
        b =>
          b.forEach(blog => {
            this.blogs.push(blog);
          }),
        error => (this.errorMessage = <any>error)
      );
    }),
  error => (this.errorMessage = <any>error)
);

AppUtilityService:

  getBlogs(blog: string): Observable<IBlogPost[]> {
    return this.http.get<IBlogPost[]>(blog);
  }

  getConfigurations(): Observable<string[]> {
    return this.http.get<string[]>(this.configuration);
  }

让它变得非常漂亮:

  ngOnInit() {
    this.initializeBlog();
  }

  private initializeBlog(): void {
    this.appUtilityService.getConfigurations().subscribe(
      b =>
        b.forEach(x => {
          this.appUtilityService.getBlogs(x).subscribe(
            b =>
              b.forEach(blog => {
                this.blogs.push(blog);
              }),
            error => (this.errorMessage = <any>error)
          );
        }),
      error => (this.errorMessage = <any>error)
    );
  }