Наблюдаемый, имеющий наблюдаемый член в шаблоне

У меня есть шаблон Angular 7, который представляет наблюдаемую book$ имея наблюдаемый translationsAsArray$ как участник:

<div *ngIf="book$ | async as book">
  <dl>
    <div *ngIf="(book.translationsAsArray$ | async) as translations">
      <dt><b class="text-muted">TRANSLATIONS</b></dt>
      <dd>
        <ul class="list-unstyled">
          <li *ngFor="let translation of translations">
            <a routerLink="/books/{{translation.rid}}">{{translation.title}}</a> ({{translation.languageAsString}})
          </li>
        </ul>
      </dd>
    </div>
  </dl>
</div>

Изменить: book.translationsAsArray$ выглядит следующим образом (только для целей тестирования):

get translationsAsArray$(): Observable<Book[]> {
    return timer(50).pipe(
        tap(time => console.log('translationsAsArray$() subsribed')),
        map(time => [new Book(this.bookService, 'abc')]));
}

У меня проблема в том, что translationsAsArray$ повторно подписывается.

Когда я меняю решение на вызов subscribe в машинописи компонентов вместо использования async труба для обоих book$ а также translationsAsArray$ проблема решена.

Вы знаете причину? Должен ли мой шаблон выглядеть иначе?

2 ответа

Чтобы избежать этого, нужно создать объект переменной шаблона со всеми наблюдаемыми в качестве свойств и использовать его для управления шаблоном:

<div *ngIf="{ book: (book$ | async), translations: (term.translationsAsArray$ | async) } as asyncs"
  <div *ngIf="asyncs.book">
    <dl>
      <div *ngIf="asyncs.translations">
        <dt><b class="text-muted">TRANSLATIONS</b></dt>
        <dd>
          <ul class="list-unstyled">
            <li *ngFor="let translation of asyncs.translations">
              <a routerLink="/books/{{translation.rid}}">{{translation.title}}</a> ({{translation.languageAsString}})
            </li>
          </ul>
        </dd>
      </div>
    </dl>
  </div>
</div>

Ваш метод получения get translationsAsArray$() возвращает новый объект Observable каждый раз, когда он вызывается. Радиально-х async pipe видит новую ссылку на объект, поэтому он подписывается на новую наблюдаемую.

get observableObj() {
  // Returns a new object each time
  return timer(50);
}

constructor() {
  console.log('Testing Observable reference equality');
  const obj1 = this.observableObj;
  const obj2 = this.observableObj;
  console.log('Different Object references?', obj1 !== obj2); // true
}

Вы должны убедиться, что ваша ссылка на Observable объект остается прежней.

Для этого измените метод get на обычное свойство объекта:

book.translationsAsArray$ = timer(50).pipe(
  tap(time => console.log('translationsAsArray subscribed')),
  map(time => ['abc'])
)

Если translationsAsArray$ должен быть получателем, вы должны кэшировать возвращаемый объект, чтобы вы не возвращали новую ссылку на объект каждый раз.

StackBlitz Демо.

Другие вопросы по тегам