k.vincent
k.vincent

Reputation: 4143

Why template reference variable using ngModel is undefined inside a for-loop?

I'am trying to get a DOM element in HTML template to disable/enable a form-button based on input value and using ngModel:#Custom_FirstName="ngModel". The input is a custom field in separated component.

My issue is that the element Custom_FirstName is always undefined and I found out that it has to do with the For Loop ngFor. When I remove ngFor, The error is fixed. But this would not solve my issue because I need the for-loop as the user can add more than one input-text and user with firstName dynamically.

Code:

<div *ngFor="let el of users.departments.admins; let i=index; trackBy: trackByFn"
    <input-text [name]="'firstanme'"                                                             
                [(ngModel)]="el.firstName"                                                          
                [ngModelOptions]="{standalone: true}"                                                      
                [readonly]="false"                                                           
                [required]="true"
                labelText="First Name"
                #Custom_FirstName="ngModel">
    </input-text>
</div>

Button:

<button [disabled]="!Custom_FirstName.value || ....>

I have been checking the official Doc, but I was not able to find the fix for that. Any hint how work around this issue?

Upvotes: 3

Views: 1148

Answers (2)

Ken Bekov
Ken Bekov

Reputation: 14015

Official documentation says:

The scope of a reference variable is the entire template. So, don't define the same variable name more than once in the same template as the runtime value will be unpredictable.

Since you already have bound input with data just track the data. Add to your component:

hasEmptyValue() {
    return users.departments.admins
        .some(admin => !admin.firstName || admin.firstName.length===0);
}

And make changes in template:

<button [disabled]="hasEmptyValue() || ....>

Upvotes: 1

Sinandro
Sinandro

Reputation: 2646

In Angular, template reference variables are scoped to the template they are defined in. So basically you can only use each #Custom_FirstName inside the div with *ngFor and not outside of it. If you don't use *ngFor the scope increase to the whole document so you don't get undefined.

To solve your problem I suggest that you wrap your code in a <form> tag and get a template reference of the form and check the validity of the form for disabling the button:

<form #myForm="ngForm">
  <div *ngFor="let el of users.departments.admins; let i=index; trackBy: trackByFn">
    <input-text [name]="'firstanme'"                                                             
                [(ngModel)]="el.firstName"                                                    
                [readonly]="false"                                                           
                [required]="true"
                labelText="First Name">
    </input-text>
  </div>
</form>

And your button will be:

<button [disabled]="myForm.invalid">

Also, make sure to add FormsModule to your module imports.

Upvotes: 0

Related Questions