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

16k 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 answers

0
Abel Valdez 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
Damián Alva 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
Ricardo Ferreira 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
ankush 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);

  } 

}