首页 > 解决方案 > Angular - 如何 MarkForCheck() ngfor 模板中的单个项目

问题描述

我对 Angular 比较陌生,所以请原谅我可能是微不足道的问题。

我也搜索了很多,发现了很多类似的问题,但没有一个真正解决我的问题。

情况

让我们假设以下组件的模板:

<div class="wrapper">
    <!-- Stuff -->
    .
    .
    .
    <div *ngFor="let group of groups">
        <button #btn (click)="onClick(btn, group)">Change group title</button>
        <div class="group-title">
            {{group.title | translate}}
        </div>
        .    
        .    
        .    
        <div *ngFor="let item of group.subGroup">
            {{item.title}}
            .    
            .    
            .    
        </div>
    </div>
<div/>

现在我希望用户能够触发一系列最终更改单个组(ngFor 中的单个项目)标题的操作/事件。

IE

onClick(btnRef, group) {
    .    
    .    
    .
    anAsyncronousEvent.subscribe(
        success => group.title = success.BrandNewTitle;
    )    
}

期望的结果

DOM 应该显示受影响组的新标题,但它没有。我也尝试过不使用“翻译”管道,但徒劳无功。

通过谷歌搜索,我似乎明白只有通过查看用于生成 ngFor 项目的对象引用,Angular 才能检测到 DOM 的变化,因此如果我只更改对象/项目的某些内部属性,则不会触发 ChangeEvent .

可能的解决方案

一个想法可能是制作组对象的深层副本并替换 ngFor 后面数组中的相应项目,但这会削弱使 Angular针对真正更改的内容刷新 DOM 的整个混乱。另一个想法可能是使用 markForCheck() 但在这里我有两个选择:

1) 在 clickHandler 中使用 markForCheck() ,但同样,这会触发组件中所有组的重新渲染。

2)我可以以某种方式仅为组标题创建一个子组件,但在我看来这有点矫枉过正,我也不确定它是否会起作用。

那么,如何强制 Angular 仅刷新组标题?

谢谢大家

编辑

好的。可能上面发布的代码有点过于简单了。

这里的这个更接近我的真实世界应用程序,并且在这里的 stackblitz 上运行,它重现了我试图解决的问题。

// Template
<div class="wrapper">
    <div *ngFor="let group of groups">
        <button #btn (click)="onClick(btn, group)">Pop away item</button>
        <div class="group-title">
            Group info: count = {{group.info | format}}
        </div>
        <div *ngFor="let item of group.items">
            &nbsp;&nbsp;&nbsp;&nbsp;Item title: "{{item.title}}"
        </div>
    </div>
</div>

//Component
onClick(btn, group: any) {
  setTimeout(() => { // In the real App this is an Observable
    let i = this.groups.indexOf(group);
    group.items.pop();
    group.info.count--;
  }, 1000);
}

我希望单击按钮后显示的项目数会减少,但事实并非如此。

标签: angularngfor

解决方案


根据您的要求,如果您不想更新整个组 [] 但只想更改 DOM 中的特定组标题,您可以做的一件事是将组的索引传递给 click 事件并使用它动态生成 id,以便您可以在触发事件时访问该 id 并更改 HTML 值。像下面的东西

<div *ngFor="let group of groups; let i = index">
    <button #btn (click)="onClick(btn, group, i)">Change group title</button>
    <div class="group-title" id="group{{i}}">
        {{group.title | translate}}
    </div>
    .    
    .    
    .    
    <div *ngFor="let item of group.subGroup">
        {{item.title}}
        .    
        .    
        .    
    </div>
</div>

在这里,您可以使用该索引“i”来更新您的 groups[],然后由于您可以使用唯一 id 访问,您可以更改该 .

onClick(btnRef, group, index) {
.    
.    
.
anAsyncronousEvent.subscribe(
    success => {
         document.getElementById(`group${index}`)
             .text(success.BrandNewTitle);
      }
    )    
  }

或者,您可以使用可以传递每个组数据的组件,在这种情况下,您可以仅显式重新加载该组组件


推荐阅读