在第一次赋值后初始值发生变化后,如何使视图反映内插变量的变化?

How to make the view reflects a change made in a interpolated variable after the initial value has been changed after the first assignment?

在应用程序中工作时,我必须将值设置为一个变量(这将获得三个不同的可能值之一),具体取决于选中的单选按钮(用户可以选择 3 个单选按钮 select).我将此值设置为对象数组的某些 属性,该对象数组仅在用户 select 按下单选按钮后才会显示。但是变量在视图中从未改变。所以我用一个简单的例子简化了这个案例,但我没有运气,我不知道为什么它不更新视图,即使变量已经被分配了新值。

请看一下这个简单的例子:

这是一个app.component.html

<ng-container *ngFor="let item of items">
  <p>{{item.name}}</p>
</ng-container>

这是它的 .ts 文件:

export class AppComponent implements OnInit {
  public firstValue: string = "Gatsu";
  constructor(private cd: ChangeDetectorRef, private nz: NgZone) {}
    ngOnInit() {
      this.init();
    }

  public items = [{ name: this.firstValue }, { name: "Kenshin" }];

  init(){
    this.firstValue = "Itachi";
    // this.cd.detectChanges();
    // this.cd.markForCheck()
    // this.nz.run(()=>this.firstValue = 'Itachi')
        alert(this.firstValue); // ---> this alerts 'Itachi'
  }      
}

我尝试应用 changeDetectorRefngZone 看看我是否有运气,但是,即使在 alert 消息上有 'Itachi',视图继续呈现初始值 'Gatsu'.

最后我把this.firstValue = "Itachi";换成this.items[0].name = "Itachi"解决了,但我一直不知道为什么第一次尝试没有成功。

好心的小伙伴们能不能让我明白第一次尝试的失败在哪里,实现我想要做的事情的最佳方法是什么?

谢谢。

您找到的解决方案是正确的。

发生这种情况是因为 firstName 的基础类型是一个字符串,它是一个值(原始)类型。因此,当您将其分配给数组中第一个点的名称 属性 时,它会复制值(而不是引用)。这意味着对 firstName 的进一步更改不会影响数组点。

这里有一篇关于 mdn 的好文章,其中详细介绍了这些不同的底层类型: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures

您遇到的问题与 Angular 无关,因为当您将变量“firstValue”设置为任何其他值时,框架不会收到任何更改通知。发生这种情况是因为您没有更改数组 [0].name 值,因为这样做时

public items = [{ name: this.firstValue }, { name: "Kenshin" }];

您没有保留对变量的引用,您只是将索引 0 处对象的键设置为变量第一个值“Gatsu”。 事实上,如果你把 console.log() 放在这里:

init(){
    this.firstValue = "Itachi";
    console.log(this.items); // <---- console.log here
    // this.cd.detectChanges();
    // this.cd.markForCheck()
    // this.nz.run(()=>this.firstValue = 'Itachi')
        alert(this.firstValue); // ---> this alerts 'Itachi'
  } 

您会注意到数组的值仍然相同。 如果您真的想更改索引 0 处对象的键“名称”,您应该像这样更改值:

this.items[0].name = "Itachi";

或者您可以只使用参考:

this.items.find(item => item.name == "Gatsu").name = "Itachi";

希望这能解决您的问题。