2

Stackblitz

I have the following model

export class Items {
  items: Map<string, string>;
  createdBy: string;
  deliveredBy: string;
}

I want to dynamically create input fields based on items in an array which I am able to I am unable to figure out how to populate data in those fields.

<form>
    <tr>
        <td *ngFor="let item of myStringArray">
            Map {{item}}<input name="value" ([ngModel])="data.items.set(item)" (ngModelChange)="onChange()">
    </td>
        <td>
            Always Present One <input ([ngModel])="data.createdBy" (ngModelChange)="onChange()" />
    </td>
        <td>
            Always Present Two<input ([ngModel])="data.deliveredBy" (ngModelChange)="onChange()" />
    </td>
    </tr>
</form>

{{ data.items | json }}

Components.ts

export class AppComponent {
  public myStringArray = ["First", "Second", "Third"];
  data = new Items();

  onChange() {
    console.log(this.data);
  }
}

I found a reference but I am unsure where I am going wrong

Reference Stackblitz

Thank you for your time and help

2
  • you need to define keys first as mentioned in "stackblitz.com/edit/…", then get it and set it's value Commented Feb 18, 2021 at 14:29
  • @abhi9393, public myStringArray = ["First", "Second", "Third"]; are the keys Commented Feb 18, 2021 at 14:38

1 Answer 1

2

There are multiple errors in your Stackblitz:

  • You cannot directly bind to a Map within an ngModel. You need to get in the ngModel and set in the ngModelChange:

    <td *ngFor="let item of myStringArray">
      Map {{item}}<input name="value" [ngModel]="data.items.get(item)" 
    (ngModelChange)="data.items.set(item, $event)">
    </td>
    
  • The syntax for the two way binding is "banana in a box" [(...)] not the opposite:

    Always Present One <input [(ngModel)]="data.createdBy" />
    
  • Are per the console error "If ngModel is used within a form tag, either the name attribute must be set or the form control must be defined as 'standalone' in ngModelOptions." you need to either set ngModelOptions or add a name field:

    Always Present One <input [(ngModel)]="data.createdBy" name="createdBy" (ngModelChange)="onChange()" />
    

Here is a new Stackblitz fixed.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much for all your help. I understand the point of having a form control. But in case where I am dynamically creating the input, how can I make sure that I pass ONLY the typed input value to the console and NOT the array. Is there a way I can just send the value? Or do I need to use array manipulations for that?
Sorry I am not sure I'm getting what you mean? Anyway, i would recommend you to use reactive forms and especially the FormArray for what you are trying to achieve. it's maybe more complex than simple models but way more powerful.
Nevermind, I was about to delete the comment because I was just not thinking correctly. What I wanted was ; if I type "abc" to the dynamic input field , I should get that to the console. (I understand how to now so no explanation required). Thank you for helping me figure this out.
ok glad you solved it! But I must say using a Map has its challenges, and I rarely use them. Also since Angular 6 you have the | keyvalue pipe that lets you iterate over a regular object like { "item1": "value1", ... } like this: <td *ngFor="let item of data.items | keyvalue"> which is super helpful and can easily replace a Map.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.