【问题标题】:Observable having observable member in templateObservable 在模板中具有 observable 成员
【发布时间】:2019-02-25 16:07:01
【问题描述】:

我有一个 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 而不是同时为 book$translationsAsArray$ 使用 async 管道时,问题就解决了。

你知道原因吗?我的模板应该看起来不同吗?

【问题讨论】:

  • 您能否发布代码以显示translationsAsArray$term 的定义位置?
  • @AlexK:我已经添加了实现。

标签: angular rxjs rxjs-pipeable-operators


【解决方案1】:

防止这种情况发生的一个技巧是创建一个模板变量对象,将所有可观察对象作为属性,并使用它来控制模板:

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

【讨论】:

  • 我注意到在将代码从源代码移动到帖子时我犯了一个错字(现已更正)。所以实际上term.translationsAsArray$应该替换为book.translationsAsArray$
【解决方案2】:

您的 getter 方法 get translationsAsArray$() 每次被调用时都会返回一个新的 Observable 对象。 Angular 的 async 管道看到一个新的对象引用,因此它订阅了新的 observable。

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 对象引用保持不变。

为此,请将 getter 更改为常规对象属性:

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

如果translationsAsArray$必须是一个getter,你应该缓存返回的对象,这样你就不会每次都返回一个新的对象引用。

StackBlitz Demo.

【讨论】:

    猜你喜欢
    • 2018-10-19
    • 2018-10-15
    • 2018-09-25
    • 2020-05-05
    • 2018-10-06
    • 2023-03-29
    • 2018-07-12
    • 2020-06-29
    • 1970-01-01
    相关资源
    最近更新 更多