Angular - How to get input value at ngFor loop with one way binding

16.1k Views Asked by At

Can you give me a way to get input value at ngFor loop with one way binding?

<div *ngFor="let d of dataList">
  <input #inputValue type="text" [ngValue]="d.value">
  <button *ngIf="!d.open" (click)="d.open = true">change</button>
  <button *ngIf="d.open" (click)="save(d.id, NEWVALUE); d.open = false;">save</button>
  <button *ngIf="d.open" (click)="d.open = false">cancel</button>
</div>`

How can I set NEWVALUE? with two-way binding is easy. but after click cancel, value already changed as I don't want. So would avoid that way.

One solution I've found is using (ngModelChange).

<div *ngFor="let d of dataList">
  <input #inputValue type="text" [ngValue]="d.value" (ngModelChange)="dataChanged($event)">
  <button *ngIf="!d.open" (click)="d.open = true">change</button>
  <button *ngIf="d.open" (click)="save(d.id); d.open = false;">save</button>
  <button *ngIf="d.open" (click)="d.open = false">cancel</button>
</div>


private newVal;
dataChanged(val) {
  this.newVal = val;
}
save(id) {
  saveDb(id, this.newVal);
}

This is not clear and optimized code as I guess.

As I know, template binding with # is also not work with ngFor. like

<div *ngFor="let d of dataList">
  <input #inputValue_{{d.id}} type="text" [ngValue]="d.value">
  <button *ngIf="d.open" (click)="save(inputValue_{{d.id}}.value); d.open = false;">save</button>
</div>

Do you have any good solution for me?

4

There are 4 best solutions below

0
On BEST ANSWER

It is not posible you must provide the template variable directly, but I did an alternative for you

HTML

<div *ngFor="let item of array">
  <input id="id_{{item.id}}" />
  <button type="button" (click)="printValue('id_'+item.id)"> buton {{item.id}}   </button>
</div>

Component

export class AppComponent  {
  array = [{id: 1}, {id: 2},{id: 3}]

  printValue(value: any){
    console.log(value);
    var containputiner = document.querySelector("#"+value);
    console.log(containputiner.value);
  }
}

Stackblitz Demo

0
On

You can create a new component that will represent an item from the list.

app-item-list.ts

import { Component, Input, Ouput, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-item-list'
  templateUrl: './app-item-list.html'
})

export class ItemListComponent {

  newValue: string;
  @Input() data: YourDataClassType;
  @Output() onUpdate: EventEmitter<{id: number, newValue: string}>;

  contructor() {

    this.onUpdate = new EventEmitter<{id: number, newValue: string}>;
    this.newValue = data.value;
  }

  save() {

    this.onUpdate.emit({id: this.data.id, newValue: this.newValue});
  }
}

app-item-list.html

<div>
  <input type="text" [(ngValue)]="newValue">
  <button *ngIf="!data.open" (click)="data.open = true">change</button>
  <button *ngIf="data.open" (click)="save(); d.open = false;">save</button>
  <button *ngIf="data.open" (click)="data.open = false">cancel</button>
</div>

parent-component.html

<app-item-list *ngFor="let d of datalist" [data]="d" (onUpdate)="save($event)" />

parent-component.ts

save($event) {
  console.log($event.id, $event.newValue);
}

Remember to include 'app-item-list' in your module declaration.

This code might need some refactor. I made it without testing and I am not using angular for a while.

0
On

You can duplicate the array and use the data from the original array to set the previous value as if it were in memory.

See my code example: https://stackblitz.com/edit/angular-a4eucy

0
On

home.component.html

<div>
<ul>
<li style="border:1px solid;width:25%;margin-bottom:1%;cursor:pointer;" *ngFor="let items of statusdata"  (click)="getData(items)"><span>{{items.id}}</span>&nbsp;&nbsp;&nbsp;&nbsp;<span>{{items.name}}</span></li>
</ul>
<select  [(ngModel)]="getOption">
<option>2019-2020</option>
</select>
</div>

home.component.ts

import { Component, OnInit } from '@angular/core';
import { CommonserviceService } from './../utilities/services/commonservice.service';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
declare var $: any;
@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
  getIt:any;
  statusdata: any;
  getOption:any;
  ngOnInit() {

      this.statusdata = [{ id: 1, name: 'Angular 2+' },
    { id: 2, name: 'Angular 4' },
    { id: 3, name: 'Angular 5' },
    { id: 4, name: 'Angular 6' },
    { id: 5, name: 'Angular 7' }
  ];
console.log(this.getOption);

  }
  getData(items){
      console.log(items.name+"and"+items.id);

  } 

}