将数组绑定到模板中的组件仅在页面加载时有效

问题描述 投票:0回答:1

我的布局模板中有一个组件(用于导航栏),并且我正在使用可注入服务,因此组件可以根据自己的逻辑更改导航栏的内容。

这是模板标记的一部分

default-layout.component.html

<app-sidebar-nav [navItems]="defaultLayoutService.items$ | async" [perfectScrollbar] [disabled]="appSidebar.minimized"></app-sidebar-nav>

default-layout.component.ts

constructor(public defaultLayoutService: DefaultLayoutService) {
}

default-layout-service.ts

import { navItems, ICustomNavData } from '../../_nav';

items$: Observable<ICustomNavData[]>;
navItems = <ICustomNavData[]>navItems; //cast to a custom interface I created.

setNavItemAttribute(itemKey: string, itemAttribute: string, text: string) {
    let menuItem = this.navItems.find(r => r.key == itemKey);

    if (menuItem && menuItem.hasOwnProperty(itemAttribute)) {
        menuItem[itemAttribute] = text;
    }

    console.log(this.navItems); //this outputs the items and shows they were modified correctly
    this.items$ = new Observable(ob => { ob.next(this.navItems); })

}

所以我有一些组件也可以访问DefaultLayoutService并使用不同的参数调用setNavItemAttribute

它有效,但仅在刷新页面时有效。在单个应用页面模式下浏览时,使用不同的参数触发对setNavItemAttribute的调用,导航项保持不变。

我在这里正确处理Observable吗?

angular typescript observable angular-services angular9
1个回答
0
投票

我在这里正确处理Observable吗?

我在这里看到2个潜在问题:

  1. 每次更新当前数组中的相应项时,您都将服务中的items$ Observable设置为新实例。
  2. 您正在将Observable的值设置为数组的相同实例,因此Angular的更改检测不会认为数组已更改(即使值within也已更改)。

让我们解决这些问题:

您可以使用中间Subject触发从服务内部在Observable上发出的值,并在想要更新值时调用.next

您可以通过正常显示从Observable构建的Subject来执行此操作。这是为了防止外部影响能够不经意/恶意地直接在对象上调用.next

看起来像这样:

export class DefaultLayoutService {
  private _navItems: <ICustomNavData[]>;
  private readonly _itemsSubject = new Subject<ICustomNavData[]>();

  items$: Observable<ICustomNavData[]> = this.itemsSubject.asObservable();

  setNavItemAttribute(itemKey: string, itemAttribute: string, text: string) {
    // code to update corresponding item in navItems array

    this._itemsSubject.next(this.navItems);
  }
}

因为Observable来自Subject,它将发出您在服务方法中传递给主题的最新值。

[请注意,当您首次初始化组件和数组时,需要将第一个值与.next一起调用_itemsSubject,以便可以在Observable上发出它。


在单个应用程序页面模式下浏览时,使用不同的参数触发对setNavItemAttribute的调用,导航项保持不变。

因为对数组itself的引用未更改,所以Angular的更改检测不会使用数组中的新值重新呈现。似乎是人们偶然发现的常见问题。

我之前做过的一种方法是使用...传播算子使用旧的数组创建一个“新的”数组。这样,引用就不同了,并触发更改检测以使用新值重新呈现。

例如:

setNavItemAttribute(...) {
  // code to update the corresponding item in the existing navItems array
  const navItemsCopy = [...this.navItems];

  // use the new array reference to trigger change detection
  this._itemsSubject.next(navItemsCopy);
}

还有许多其他方法可以执行此操作,因此请四处看看,以找出最适合您的情况并适合您的感觉。

© www.soinside.com 2019 - 2024. All rights reserved.