1

I'm trying to use *ngFor for a set of identical inputs save for the property the input should bind to.

<mat-form-field *ngFor="let prop of [ID, Name, Nickname]">
    <input matInput type="text" placeholder="prop.key" #propInput [(ngModel)]="prop">
    <button mat-icon-button matSuffix mat-icon-button *ngIf="propInput.value" (click)="prop='';">
        <mat-icon>close</mat-icon>
    </button>
</mat-form-field>

 <!-- bind test -->
<input matInput type="text" placeholder="Name Test" #propInput [(ngModel)]="Name">

prop.key does not work, but that is a separate question.

Here is the tethered component:

import { Component } from '@angular/core';
import { EntitySrcService } from '../entity-src.service';

@Component({
  selector: 'app-entity-table',
  templateUrl: './entity-table.component.html',
  styleUrls: ['./entity-table.component.less']
})

export class EntityTableComponent {

  constructor(
    private entitySrc: EntitySrcService
    ) {}

  public get ID(): string {
    return this.entitySrc.id;
  }

  public set ID(value: String) {
    this.entitySrc.id = value;
  }

  public get Name(): string {
    return this.entitySrc.name;
  }

  public set Name(value: String) {
    this.entitySrc.name = value;
  }

  public get Nickname(): string {
    return this.entitySrc.altName;
  }

  public set Nickname(value: String) {
    this.entitySrc.altName = value;
  }

}

For the most part this seems to work as expected, but it seems the [(ngModel)] bind is only reading the property and not writing to it. So for example, if I update the bind test input, the Name field in the ngFor loop updates to match, but updating the one in the ngFor loop does not update the one in the test.

I'm using get/set properties in the component to proxy to the actually storage location, but my understanding is that a get/set property should act the same as a normal property (and using a normal property has the same one way bind behavior).

So how do I properly iterate over a set of properties that I want to bind to?

Alex Vovchuk
  • 2,828
  • 4
  • 19
  • 40
Tezra
  • 8,463
  • 3
  • 31
  • 68
  • can you post your json object structure, if possible create a stackblitz – Aravind Sep 27 '19 at 14:12
  • What is the stored data in `ID`, `Name` and `Nickname` variables..? – Rohit Sharma Sep 27 '19 at 14:15
  • 1
    Possible duplicate of [access key and value of object using \*ngFor](https://stackoverflow.com/questions/35534959/access-key-and-value-of-object-using-ngfor) – Barkha Sep 27 '19 at 14:17
  • your approach is weird here. Just make a component and put it on the page 3 times. – bryan60 Sep 27 '19 at 14:18
  • post your component code. It'll probably help a lot – Damian C Sep 27 '19 at 14:27
  • 1
    A possible workaround is to use a set of property names, as shown in [this stackblitz](https://stackblitz.com/edit/angular-ze2gqb?file=src%2Fapp%2Fapp.component.html). – ConnorsFan Sep 27 '19 at 14:59
  • 1
    @ConnorsFan can you make that an answer? That is almost exactly what I want. I feel there should be a better way to iterate over ngModel bindable properties for more complex cases, but for now at least the `this[prop]` method works. – Tezra Sep 27 '19 at 16:26
  • @Barkha I don't need key-value pairs, I want to iterate over a set of ngModel bindable properties. The fact that what I have half works implies there should be a way to properly do it. – Tezra Sep 27 '19 at 16:39

3 Answers3

2

It looks that [ID, Name, Nickname] are value types. In this case *ngFor just uses their values without binding to the original variables. If you still need binding, you should consider transforming them to reference types.

For example you could put them into the object, like person or options and iterate object properties using KeyValuePipe: How to iterate object keys using *ngFor

options: {[key: number]: string} = {ID: '1', Name: 'bar', Nickname: 'foo'};

<div *ngFor="let item of options | keyvalue">
Alex Vovchuk
  • 2,828
  • 4
  • 19
  • 40
2

The array [ID, Name, Nickname] contains the values of the three properties, not their references. The two-way binding will modify the array items instead of the original properties (for that to work, you must refer to the items by their index and track the array by index, as shown in this answer).

To achieve two-way binding of the component properties, you could use an array of property names, and refer to each property with this[prop]:

<mat-form-field *ngFor="let prop of ['ID', 'Name', 'Nickname']">
  <input [(ngModel)]="this[prop]" ... >
  ...
</mat-form-field>

See this stackblitz for a demo.

ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
0

In Angular 6.1 the KeyValuePipe was introduced which allows you to iterate object properties:

<div *ngFor="let item of object | keyvalue">
  {{item.key}}:{{item.value}}
</div>

Docs: https://angular.io/api/common/KeyValuePipe

Eudz
  • 540
  • 6
  • 19
  • I don't need key-value pairs. I'm specifically looking to use ngFor over a set a properties to be bound to ngModel. – Tezra Sep 27 '19 at 16:42