How to set unique template reference variables ins

2020-02-04 07:04发布

问题:

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.

回答1:

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>


回答2:

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.



回答3:

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