使用*ngFor和[(ngModel)]来用Map改变对象数组



我有一个包含对象数组的类:

export class MyObject {
sections: Section[]
}

Section类包含一个Map:

export class Section {
dataPoints: Map<string, string>
}

我想向前端的用户呈现一个MyObject类的对象,并让用户更改其内容。我有一个问题,在HTML代码的组件:

<ul>
<li *ngFor="let section of this.myObject; index as sectionsIndex">
<ul>
<li *ngFor="let dataPoint of section.dataPoints | keyvalue">
<mat-form-field appearance="fill">
<mat-label>Label:</mat-label>
<input matInput placeholder="Label input field placeholder"
[(ngModel)]="this.myObject.sections[sectionsIndex].dataPoints[dataPoint.key]">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Content:</mat-label>
<input matInput placeholder="Content input field placeholder"
[(ngModel)]="this.myObject.sections[sectionsIndex].dataPoints[dataPoint.value]">
</mat-form-field>
</li>
</ul>
</li>
</ul>

如果没有键值管道,我在控制台上得到这个错误:"错误:NG02200:无法找到类型为'object'的不同支持对象'[object Map]'。NgFor只支持绑定到Iterables,比如array。您是想使用键值管道吗?";

我遵循如何使用ngFor循环Map包含键作为字符串和值作为映射迭代,这将我带到了键值管道,但是通过[(ngModel)]="this.myObject.sections[sectionsIndex].dataPoints[dataPoint.key]"访问原始对象导致编译器错误;元素隐式具有'any'类型,因为类型'Map<string,>'没有索引签名。你是想叫"get"吗?以及同样的错误信息"您是否打算调用'set'?">

用户应该能够在Sections中改变dataPoints地图的内容以及我在代码示例中没有提到的MyObject的其他类变量,以及从数组中添加和删除部分,并通过使用添加/删除按钮从地图dataPoints中添加和删除元素,我在代码中省略了这些按钮,以便集中精力解决问题。

处理使用Map更改对象数组的问题的最佳实践是什么?是什么导致了代码中的错误?

我很难确切地告诉你在做什么,但有几件事要考虑:

  1. 不要用"this"。'在你的html。把它去掉

  2. this.myObject.sections[sectionsIndex]是没有意义的,因为你已经可以通过简单地使用:section

  3. 你可能只是想说:[(ngModel)]="dataPoint"

在Rick的回答的帮助下,我找到了解决办法。键值管道仍然是必需的:

<ul>
<li *ngFor="let section of this.myObject; index as sectionsIndex">
<ul>
<li *ngFor="let dataPoint of section.dataPoints | keyvalue">
<mat-form-field appearance="fill">
<mat-label>Label:</mat-label>
<input matInput placeholder="Label input field placeholder"
[(ngModel)]="dataPoint.key">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Content:</mat-label>
<input matInput placeholder="Content input field placeholder"
[(ngModel)]="dataPoint.value">
</mat-form-field>
</li>
</ul>
</li>
</ul>

这有点棘手,因为这些值是基本值(字符串),所以它们不是通过键值管道通过引用传递给您的。这意味着更新该值不会对实际的地图产生影响。但是,您可以简单地使用(ngModelChange)来定制值更改时发生的情况。删除ngModel中的圆括号,以便值只在中的传递给键值管道的输入。

如果值是对象,您可以使用双向绑定[(ngModel)]与它们的一个属性,因为您将有对该对象的引用。

注意,这里还需要一个自定义的track by函数,否则Angular会在每次值改变时渲染输入,导致用户失去对输入的关注。

Stackblitz: https://stackblitz.com/edit/angular-ivy-ejgn4p?file=src/app/app.component.html

<ul>
<li *ngFor="let section of this.myObject.sections">
<ul>
<li *ngFor="let dataPoint of section.dataPoints | keyvalue; trackBy: trackByKey">
<label>{{dataPoint.key}}
<input
[ngModel]="dataPoint.value"
(ngModelChange)="section.dataPoints.set(dataPoint.key, $event)"
/>
</label>
</li>
</ul>
</li>
</ul>
export class AppComponent {
myObject: MyObject = {
sections: [
{
dataPoints: new Map([
['k11', 'v11'],
['k12', 'v12'],
['k13', 'v13'],
]),
},
{
dataPoints: new Map([
['k21', 'v21'],
['k22', 'v22'],
['k23', 'v23'],
]),
},
],
};
trackByKey(i: number, d: { key: string; value: string }) {
return d.key;
}
}

最新更新