Невозможно поместить подписанное наблюдаемое в коллекцию как строку - PullRequest
2 голосов
/ 30 июня 2019

Я новичок в машинописи и JavaScript, и мне очень трудно понять, как работают коллекции и файлы. Я пытаюсь получить данные из файла json, в чем я преуспел, хотя, когда я помещаю их в коллекцию, в коллекции нет данных.

Вот код:

В моем классе обслуживания:

  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;
  }

Где мне вводят мой класс обслуживания:

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 и как их правильно вернуть

Ответы [ 2 ]

0 голосов
/ 02 июля 2019

Оказывается, да, действительно ...

Здесь я сделал это красиво:

OnInit:

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)
    );
  }
0 голосов
/ 01 июля 2019

Внутри getConfigurations вы вызываете асинхронный HTTP-запрос.Так что это нормально, что configurationsData пусто вне метода subscribe.

Здесь я использую мощный из RxJS , чтобы упростить код и избежать использования Array.pushи вложенный subscribe().

1) Базовый метод асинхронной службы для получения данных

Поэтому getConfigurations должен возвращать Observable:

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

А также getBlogs должен возвращать 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()
  )
}

Что означает, получить всю коллекцию путей к блогам, для каждого массива путей, для каждого пути, получить сообщения в блоге, а затем вернуть уникальный массив всех сообщений.

Наконецвнутри вашего компонента вы звоните 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>

Проверьте мою полную демонстрацию этой альтернативы RxJS на Stackbliz.

Рекомендуется прочитать на носителе от Томаса Траяна

...