简体   繁体   English

*对于来自BehaviorSubject的observable的异步管道,ngIf似乎在加载数据之前不正确地激活

[英]*ngIf with async pipe for observable from BehaviorSubject seem to activate incorrectly until data is loaded

If the array in response is empty I want to display a message, otherwise the elements of the array. 如果响应中的数组为空,我想显示一条消息,否则就是数组的元素。

In case the response has a non-empty array the *ngIf condition evalutes to true and the message is displayed until the data is loaded. 如果响应具有非空数组,则* ngIf条件将evalutestrue,并且将显示消息, 直到加载数据为止

Html template snippet: Html模板代码段:

<div *ngIf="personalAndStarredBookmarks$ && (personalAndStarredBookmarks$ | async)?.size === 0; else personalBookmarksList" class="missing-category-bookmarks-message  alert alert-info">
  <p>No bookmarks yet</p>
</div>
<ng-template #personalBookmarksList>
  <app-async-bookmark-list [bookmarks]="personalAndStarredBookmarks$" [shownSize]="10" [userData]="userData"></app-async-bookmark-list>
</ng-template>

Component snippet: 组件片段:

import { List } from 'immutable';

export class PersonalBookmarksListComponent implements OnInit {

  personalAndStarredBookmarks$: Observable<List<Bookmark>>;

  ngOnInit(): void {

    this.personalAndStarredBookmarks$ = this.personalBookmarksStore.getPersonalBookmarks();
  }
  ...
}

The store uses a BehaviourSubject where it holds the response from a service that actually does the HTTP call. 该商店使用BehaviourSubject ,它保存来自实际执行HTTP调用的服务的响应。

Store snippet 存储片段

@Injectable()
export class PersonalBookmarksStore {

  private _personalBookmarks: BehaviorSubject<List<Bookmark>> = new BehaviorSubject(List([]));

  constructor(private personalBookmarkService: PersonalBookmarkService,
              private keycloakService: KeycloakService
  ) {
    keycloakService.loadUserProfile().then(keycloakProfile => {
      this.userId = keycloakProfile.id;
      this.loadInitialData();
    });
  }

  private loadInitialData() {
    this.personalBookmarkService.getAllPersonalBookmarks(this.userId)
      .subscribe(
        data => {
          let bookmarks: Bookmark[] = <Bookmark[]>data;
          this._personalBookmarks.next(List(bookmarks));
        },
        err => console.error('Error retrieving bookmarks', err)
      );
  }

  getPersonalBookmarks(): Observable<List<Bookmark>> {
    return this._personalBookmarks.asObservable();
  }
  ...
}

If I am calling directly the Service (not the Store) in the component it behaves as expected... 如果我直接调用组件中的服务(而不是商店),它的行为符合预期......

You should restructure your template to handle the async calls efficiently by assigning a local variable as 您应该重新构建模板,以通过将局部变量指定为有效地处理异步调用

<ng-content*ngIf="personalAndStarredBookmarks$ | async as personalAndStarredBookmarks">
    <div *ngIf="personalAndStarredBookmarks.size === 0; else personalBookmarksList" 
        class="missing-category-bookmarks-message  alert alert-info">
        <p>No bookmarks yet</p>
    </div>
    <ng-template #personalBookmarksList>
        <app-async-bookmark-list [bookmarks]="personalAndStarredBookmarks" [shownSize]="10"
            [userData]="userData">
        </app-async-bookmark-list>
    </ng-template>
<ng-content>

With this, you can efficiently handle all the conditions and the main content loads only after the async call is resolved. 这样,只有在解析异步调用后,才能有效地处理所有条件和主要内容。

See a DEMO HERE 这里看一个演示

The culprit is the initialisation of the BehaviorSubject with an empty list, which gets emitted and the condition evaluates to true: 罪魁祸首是使用列表初始化BehaviorSubject,该列表将被释放并且条件的计算结果为true:

private _personalBookmarks: BehaviorSubject<List<Bookmark>> = new BehaviorSubject(List([]));

Fix - init the BehaviorSubject with a null or undefined 修复 - 使用nullundefined初始化BehaviorSubject

private _personalBookmarks: BehaviorSubject<List<Bookmark>> = new BehaviorSubject(null);

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

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