Reputation: 409
I'm trying to get this component working that will take an object of key/value pairs, display them in input tags, and change them on the original object. So say I have an object like:
{
name: "John",
id: "12345",
preferences: { foo: "bar", biz: "baz" }
}
I can call <key-value [obj]="profile.preferences"></key-value>
and the data will be printed in two pairs in input tags. If I then changed "foo" to "qux" the property key would change. To accomplish this I have a key-value component that really simply does:
<div *ngFor="let pref of obj | keyvalue">
<input [(ngModel)]="pref.key"><br />
<input [(ngModel)]="pref.value"><br />
</div>
Which I feel is very simple. It's an object passed in, so it's a reference to the original object, and the ngModels in literally every other input of my application work so I assume that's not wrong.
I've done a lot of looking around and I did actually get it working if I had a "changeKey/changeValue" function that would change this.obj in the component rather than relying on binding:
<div *ngFor="let pref of obj | keyvalue">
<input (change)="changeKey(/*???*/)" [ngModel]="pref.key"><br />
<input (change)="changeValue(pref.key, pref.value) [ngModel]="pref.value"><br />
</div>
That works for the changeValue because I have the key I need to change and the new value. But the issue with the changeKey is because pref.key has been changed I don't know which key to update.
I feel like this shouldn't be that difficult, I'm still quite new to Angular and I'm hoping someone here knows what's going on. Thanks.
Upvotes: 8
Views: 9111
Reputation: 1556
I needed to do it like this for example:
<span *ngIf="hasProp(subChart.series, 'params')" >
<mat-form-field class="example-full-width" *ngFor="let keyVal of subChart.series.params | keyvalue">
<mat-label>{{keyVal.key}}</mat-label>
<input matInput type="number" [(ngModel)]="subChart.series.params[castToString(keyVal.key)]"
[value]="subChart.series.params[castToString(keyVal.key)]" />
</mat-form-field>
</span>
Which uses these functions:
public castToString(obj: any): string{
return obj as string;
}
public hasProp(obj: any, name: string) {
return obj.hasOwnProperty(name);
}
Upvotes: 0
Reputation: 2932
KeyValuePipe in a nutshell:
Transforms Object or Map into an array of key value pairs.
The keyvalue
pipe creates a new array from a given object, and as such, binding to it will not affect the original object.
As for your issue, instead of using the (change)
event listener, you can bind ngModel
to your original object and point to it directly:
<div *ngFor="let prop of myObject | keyvalue">
<input [(ngModel)]="myObject[prop.key]">
</div>
Upvotes: 11
Reputation: 462
You can define the changeKey
function like the following code.
In Component
changeKey(prevKey, newKey) {
const value = this.obj[prevKey];
delete this.obj[prevKey];
this.obj[newKey] = value;
}
In HTML
<input (change)="changeKey(pref.key, $event.target.value)" [ngModel]="pref.key"><br />
I created a working example on stackblitz.
Upvotes: 4