Оберегаемый в оберегаемый с условиями — Angular 10

#angular #rxjs #observable

#угловой #rxjs #наблюдаемый

Вопрос:

В форме я хочу добавить книгу.

Пользователь вручную вводит имя автора. Когда пользователь отправляет форму, он должен сначала проверить, существует ли автор :

  • если нет, это создает автора
  • Если он уже существует, он просто извлекает информацию об авторах (id)
  • Затем он добавляет книгу с идентификатором автора

Я думаю, что смогу заставить его работать с :

 formSubmit() {
  this.authorService.getByName(this.authorName).subscribe(author => {
    // Author exists
    if (author.id) {
      this.book.author = author;
      this.bookService.add(this.book).subscribe(() => {
        // Book added
      });
    } else {
      const authorObj: AuthorInterface = {
        fullName = this.authorName;
      }
      this.authorService.add(authorObj); subscribe(author => {
        this.book.author = author;
        this.bookService.add(this.book).subscribe(() => {
          // Book added
        });
      })
    }
  });
}
  

Но это действительно ужасно, я уверен, что смогу сделать его чище, rxjs но не могу найти решение. Я немного смущен тем, как использовать все эти функции.

Я буду признателен за некоторую помощь. Большое спасибо 🙂

Комментарии:

1. Некоторые вопросы: Цель состоит в том, чтобы сохранить автора в объекте book? Если вы запрашиваете несуществующего автора по имени, он все равно возвращает объект author, но без идентификатора? Зачем вы добавляете книгу, если «Автор существует»? У меня есть представление о ваших требованиях, и, насколько я вижу проблему, вы можете решить ее с помощью одной подписки во время выполнения. Поэтому мне нужны ответы на мои три вопроса.

2. Цель состоит в том, чтобы сохранить книгу с автором, но если автор уже добавлен, я хочу извлечь его и добавить в книгу. На самом деле, это пример, над которым я не работаю над книгами и автором, но мы можем представить, что если пользователь не существует, API возвращает и пустой объект (я использую платформу API для возврата). Если автор существует, я могу захотеть добавить новую книгу, которую он только что написал 🙂

Ответ №1:

Вы можете использовать switchMap. Этот оператор подписывается на другую наблюдаемую, которую вы передаете ему, и выводит ее результат.

 this.authorService.getByName(this.authorName)
.pipe(
  switchMap(author => {
    if (author.id) {
      this.book.author = author;
      return this.bookService.add(this.book).pipe(...);
    }
    return this.authorService.add(authorObj).pipe(
      switchMap(author => ...)
    );
  })
)
.subscribe();
  

Ответ №2:

если это большое наблюдаемое значение (много передаваемых значений), вам лучше остаться с if else

 this.authorService
  .getByName(this.authorName)
  .pipe(
    mergeMap((author: any) => {
      if (author.id) {
        this.book.author = author;
        return this.bookService.add(this.book).pipe(
          tap(() => {
            console.log("book added");
          })
        );
      } else {
        const authorObj: AuthorInterface = {
          fullName: this.authorName
        };
        return this.authorService.add(authorObj).pipe(
          mergeMap((author: any) => {
            this.book.author = author;
            return this.bookService.add(this.book).pipe(
              tap(() => {
                console.log("book added");
              })
            );
          })
        );
      }
    })
  )
  .subscribe(() => console.log("job done"));
  

в качестве альтернативы вы можете сделать это:

   const firstObservable = this.authorService.getByName(this.authorName).pipe(
      filter((author: any) => author.id != null),
      mergeMap(author => {
        this.book.author = author;
        return this.bookService.add(this.book).pipe(
          tap(() => {
            console.log("book added");
          })
        );
      })
    );

    const secondObservable = this.authorService.getByName(this.authorName).pipe(
      filter((author: any) => author.id == null),
      mergeMap((author: any) => {
        const authorObj: AuthorInterface = {
          fullName: this.authorName
        };
        return this.authorService.add(authorObj).pipe(
          mergeMap((author: any) => {
            this.book.author = author;
            return this.bookService.add(this.book).pipe(
              tap(() => {
                console.log("book added");
              })
            );
          })
        );
      })
    );

    merge(firstObservable, secondObservable).subscribe(author =>
      console.log("job done")
    );