简体   繁体   English

ngFor在ngIf中使用异步管道进行观测

[英]ngFor Observable with async pipe in ngIf displays no results

I've got an input with dropdown list that isn't displaying results. 我有一个带有下拉列表的输入,它不显示结果。 It in an ngIf with async. 它在带有异步的ngIf中。 The dropdown list is displayed when I remove the ngIf code so I think it must be either the ngIf check or how I've setup the test observable service. 当我删除ngIf代码时,将显示下拉列表,因此我认为它必须是ngIf检查或如何设置测试可观察服务。 When I press a key entering 1 value nothing is displayed, the second time I enter a key it displays the list. 当我按下输入1值的键时,什么都没有显示,第二次输入键时,它显示列表。

<div class="format-options" *ngIf="(definitions | async)?.length > 0">
  <div *ngFor="let definition of definitions | async" class="search-result">
    <div>{{definition.name}}</div>
    <div>{{definition.description}}</div>
  </div>
</div>

Search Service: 搜索服务:

searchTerm(term: string): Observable<Array<ObjectDefinition>>

    let observer = new Observable<Array<ObjectDefinition>>((subscription) => {

      const timer$ = interval(1000);

      timer$.subscribe(() => {
        console.log('timer 1 second');
        subscription.next(this.objectDefinitions);
        subscription.complete();
      });

    });

    return observer;
}

Component: 零件:

constructor(private definitionService: DefinitionService) {
    this.definitions = this.searchInput.valueChanges
                        .pipe(
                            tap(value => console.log('input')),
                            //startWith(''),
                            debounceTime(500),
                            //distinctUntilChanged(),
                            switchMap(value => this.definitionService.searchTerm(value))
                        );
  }

I guess the first *ngIf subscribes through the async pipe. 我猜第一个*ngIf通过async管道订阅。 Once this returns a result, the observable completes, and the *ngFor tries to susbcribe to an already completed observable which does not replays it's last emit. 返回结果后,可观察对象将完成,并且*ngFor尝试使用一个已完成的可观察对象,该可观察对象不会重播它的最后一个发射。 You can fix this by adding a shareReplay(1) pipe: 您可以通过添加shareReplay(1)管道来解决此问题:

this.definitions = this.searchInput.valueChanges.pipe(
  tap(value => console.log('input')),
  debounceTime(500),
  switchMap(value => this.definitionService.searchTerm(value)),
  shareReplay(1)
);

The whole searchTerm observable looks a bit weirdly constructed though, and you should have a look at how to improve that one, but it's a bit difficult to see what you want to achieve there. 整个searchTerm可观察的结构看起来有些奇怪,您应该看看如何改进它,但是要在此处实现目标却有些困难。 Are you trying to debounce it by 1000ms and only emit once? 您是否要以1000ms的时间对其进行反跳并仅发射一次?

To prevent the use of double subscriptions in your template, you can also change your template a bit: 为了防止在模板中使用双重订阅,您还可以对模板进行一些更改:

<ng-container *ngIf="definitions | async as defs">
  <div class="format-options" *ngIf="defs.length > 0">
    <div *ngFor="let definition of defs" class="search-result">
      <div>{{definition.name}}</div>
      <div>{{definition.description}}</div>
    </div>
  </div>
</ng-container>

You can set the result of the async operation directly in the *ngIf directive like that: 您可以像这样直接在* ngIf指令中设置异步操作的结果:

<div class="format-options" *ngIf="definitions | async as defs">
  <div *ngFor="let definition of defs" class="search-result">
    <div>{{definition.name}}</div>
    <div>{{definition.description}}</div>
  </div>
</div>

Then no need for the second async pipe. 然后,无需第二个异步管道。

PS: Never subscribe in your services, pefere using RxJs operators. PS:永远不要订阅您的服务,请使用RxJs运算符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM