Tezra
Tezra

Reputation: 8833

How to *ngFor over set of ngModel bindable properties

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?

Upvotes: 1

Views: 2162

Answers (3)

Martin Parenteau
Martin Parenteau

Reputation: 73721

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.

Upvotes: 2

Alex Vovchuk
Alex Vovchuk

Reputation: 2926

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">

Upvotes: 2

Eudz
Eudz

Reputation: 598

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

Upvotes: 0

Related Questions