I have a bunch of input fields in a *ngFor
loop. The documentation says that template reference variables should be unique. Is there a way to do something like #attendee-{{person.id}}
to make it unique?
<div *ngFor="let person of attendeesList">
<input #attendee [ngModel]="person.name" (blur)="changeName(attendee.value)"/>
</div>
(I know that there is the option of doing (ngModelChange)="changeName($event)"
but there are reasons I need to use blur instead. Specifically, I don't want the model to change until the person is done typing the name and we have validated that the name is not empty and not a duplicate name.
Your template reference variable is already unique because you use it inside embedded view scope:
<div *ngFor="let person of attendeesList">
<input #attendee [ngModel]="person.name" (blur)="person.name = attendee.value"/>
</div>
Working Example
But you can even omit template reference variable as shown below:
<div *ngFor="let person of attendeesList">
<input [ngModel]="person.name" (blur)="person.name = $event.target.value"/>
</div>
Template variables need to be unique with respect to the template rather than the rendering of the template (the actual values). You want to use ViewChildren.
@ViewChildren('attendee') attendeeInputs: QueryList<ElementRef>;
You can treat attendeeInputs
as a QueryList and operate on each attendee input individually as needed based on iteration of the indices.
If you have an iterable series of Inputs in your form and a decent amount of logic regarding how you want the form to respond to user input the ReactiveFormsModule
is going to be a much better fit. This way you don't have to worry about template reference variables and can interact with the FormControls directly.
Essentially with Reactive Forms it would look something like
Component
// Initialize your Form
initForm(): void {
this.Form = this._FormBuilder.group({
arrayOfInputs: this._FormBuilder.array(initArray())
})
}
// Initialize the Array of Inputs
initArray(): FormGroup[] {
return [
{ this._FormBuilder.group({ inputValue: [''] }),
{ this._FormBuilder.group({ inputValue: [''] }),
{ this._FormBuilder.group({ inputValue: [''] })
]
}
Template
<ng-container formArrayName="formArray">
<div [formGroupName]="i" *ngFor="let Inputs of Form.get('arrayOfInputs').controls; let i=index">
<input formControlName="inputValue" type="text">
</div>
</ng-container>
There's a few things missing here, but generally this is how I build forms that have interable inputs. The major difference is that usually when initializing the FormArray, I am using data pulled from somewhere. It really helps to build your forms in logical chunks.
Reactive Forms