【问题标题】:Angular view ngFor not displaying observable collection after it has been updated in ngOnInitAngular 视图 ngFor 在 ngOnInit 中更新后不显示可观察的集合
【发布时间】:2020-06-19 05:50:11
【问题描述】:

我有一个使用 NGRX 的 Angular 9 应用程序,该应用程序大部分使用 observables/subjects 和 assync 管道。

我有一个具有以下 HTML 的导航栏组件:

<ul class="navbar-nav">
    <li class="nav-item" *ngFor="let menuItem of navbarMenuItems | async">
      <a id="{{ menuItem.id }}" [routerLink]="menuItem.routerLink" class="nav-link">
        <span><i class="icon" [className]="menuItem.iconClass"></i>{{ menuItem.translationKey | translate }}</span>
    </a>
  </li>
</ul> 

navbarMenuItems 是我在组件 ngOnInit 方法中附加的可观察数组:

this.navbarMenuItems = this.navbarService.getNavbarMenuItems();

NavbarService 如下所示:

@Injectable({
  providedIn: "root"
})
export class NavbarService {

  public navbarMenuItems = new Subject<NavbarActionModel[]>();

  constructor(
  ) { }

  updateNavbarMenuItems(items: NavbarActionModel[]) {
    this.navbarMenuItems.next(items);
  }

  getNavbarMenuItems(): Observable<any> {
    return this.navbarMenuItems.asObservable();
  }
}

从任何其他组件调用 NavbarService updateNavbarMenuItems() 方法时一切正常(即导航栏更新并显示您发送的操作)。

但是,如果我在 NavbarComponent(即带有 HTML 的那个)ngOnInit 方法中调用 updateNavbarMenuItems(),则 HTML 不会更新。 但是如果我在 ngAfterViewInit() 方法中调用 update 方法,它们确实会出现。

我的一位同事帮助我解决了这个问题,并告诉我这是因为 *ngFor 没有及时呈现的竞争条件,这似乎是正确的。但是,这对我来说似乎真的很奇怪,我觉得我一定做错了什么,如果有人可以提供帮助,我的代码/最佳实践中还有另一个错误?

【问题讨论】:

  • 只要您在 ~create~ set this.navbarMenuItems(在您的导航栏组件内)更新值,Observable 流就应该正确更新。
  • 我会(或者至少我认为我会通过调试工具),这就是为什么我认为我的问题可能与渲染无关!这感觉与我所做的许多其他工作相似(即将 ngFor 集合设置为可观察对象)。
  • 我个人不会使用async 管道。如果您只是在组件中订阅该主题,并在那里分配结果,它应该可以正常工作。
  • 为什么不使用 aync 管道?这对我来说感觉像是一个更清洁的解决方案,但也许我错了?
  • 另外,您可以尝试使用BehaviorSubjectReplaySubject。另一种选择是初始化 navbarMenuItems = of(EMPTY) 以确保您不会遇到 DOM 渲染问题。

标签: angular observable ngrx


【解决方案1】:

Subject 没有在Subscription 上返回任何值,它只触发.next(value) 发出的新值。

BehaviorSubject 还返回每个新 Subscription 上最后发出的值。

在这种情况下,您应该使用 BehaviorSubject 来确保在 async 管道订阅 observable 的新时间发出该值。

检查此Stackblitz demo

您可以看到,如果我们模拟延迟(使用setTimeoutHTTP 请求...),该值将在视图初始化后发出,因此async 管道已经订阅。

如果是BehaviorSubject,当视图初始化时,navbarMenuItems | async 将接收当前值(在视图初始化期间已经发出),然后显式地将视图标记为脏(需要更新)。

更新(附加说明):

OnInit 在渲染过程开始时被调用。稍后绑定Pipe 指令,并调用transform 方法。在第一次调用期间,AsyncPipe 订阅了Observable

因此,AsyncPipeOnInit 执行后订阅Observable

但在我们的例子中,Observable 的值已经发出了一次。

【讨论】:

  • 所以我猜这种情况下的“订阅”是在渲染异步管道时,这发生在我分配下一个值之后?
猜你喜欢
  • 2021-05-27
  • 1970-01-01
  • 1970-01-01
  • 2017-02-28
  • 2018-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多