Mahi Tej Gvp
Mahi Tej Gvp

Reputation: 1034

append String to ngModel to get an expression

I have a Business Object Car{id:2,name:ford,modelNo:123} I also have a MetaData class for CarMetaData{columnName:string,type:text,required:true} each attribute has it's own CarMetaData object how can I display Car data in a form in such a way using an Array of CarMetaData objects

In the template.html file

<form #carForm='ngForm'>
 <div class="form-group" *ngFor="let metaData of metadata" >
   <input [(ngModel)]="car[metaData.columnName]" name="metaData.columnName" 
    type="text">
 </div>
</form>

In the component file

car:Car;
metadata:CarMetaData[];

The above method isn't working because of the [] in car[meta.columnName] in the ngModel is there a way an expression can be worked out in *ngFor or [(ngModle)] to calculate columName

Upvotes: 3

Views: 3367

Answers (2)

Julius Dzidzevičius
Julius Dzidzevičius

Reputation: 11000

Very stupid mistake. Please try this:

<div *ngFor="let meta of metaData;">
  <input [(ngModel)]="car[meta.columnName]" name="{{meta.columnName}}"  />
  {{meta.columnName}}
</div>


Old answer:

But first - your loop (meta in metaData) is wrong as you loop array, not object. So you better do let meta of metaData, let i = index.

And the interesting part is how ngModel sets the value of inputs in ngFor. If you try this:

<div *ngFor="let meta of metaData; let i = index">
  <input [(ngModel)]="car[meta.columnName]" name="meta.columnName"  />
  {{meta.columnName}}
</div>

You will see that input value is the same of all inputs (it was picked from the first ngFor iteration and repeated to all inputs). However, {{meta.columnName}} prints correct values. So there is some scoping issue. Other strange thing - its definitely related with ngForm and input's name property. If you move that outside of the form - all happens as expected. And if you:

<div *ngFor="let meta of metaData; let i = index">
  <input [(ngModel)]="car[meta.columnName]" name="{{metaData[i].columnName}}"  />
  {{meta.columnName}}
</div>

Inside the form - again, all works well. So that might be your workaround.

Here is a DEMO. Hopefully someone will explain it further.

Upvotes: 1

user6749601
user6749601

Reputation:

I'd suggest to put both objects in a wrapper-object. e.g.

export class CarWrapper {
    constructor(
       car: Car,
       carMetaData: CarMetaData
    ) {}
}

Then build a method that joins both objects in this wrapper

private carWrapper: Array<CarWrapper> = [];

private fillCarWrapper(): void {
    // your code here
}

And in your template you act like this

<form #carForm='ngForm'>
   <div class="form-group" *ngFor="let wrapper of carWrapper">
      <input [(ngModel)]="wrapper.car" name="wrapper.carMetaData.columName" type="text">
   </div>
</form>

Upvotes: 1

Related Questions