Search code examples
javascriptangularngforangular-ng-ifangular-template

use ngFor loop in Angular 6 to dynamically create array of input elements and add dynamical validation based on template reference variables


I would like to create dynamically 3 input tags in Angular 6 to not copy/paste html code because that input elements have similar html and functionality.

For this purpose I created an array "reusableItems" inside component and initialize it :

    let numberOfInputElements = 3;        
    for (let i = 0; i < numberOfInputElements; i++) {          
      this.reusableItems.push({
        answer: 'Answer ' + (i +1),
        passwordRecoveryAnswer: this.user['passwordRecoveryAnswer' + (i + 1)]
      });
    }

Then I put code inside my html :

<div *ngFor="let item of dropDownDataManagerService.reusableItems" >
  <li class="col-xs-12 pl-lg pr0 pv-sm bd1-bottom">
    <div class="col-xs-4 ph0 pt"> {{item.answerTitle}}</div>
    <div class="col-xs-8">
      <input type="text" name={{item.answer}} ref-{{item.answer}}="ngModel" class="col-sm-12 k-textbox ph0"
             [(ngModel)]=item.passwordRecoveryAnswer
             [pattern]="[a-z]"
             required autocomplete="off"/>

    </div>
  </li>
</div>

It seems works fine but then I need to add error messages when these fields will be empty and not match to pattern. Something like :

<div *ngIf="__{{item.answer}}__.errors?.required ">
  {{'Please provide an answer' | translate}}
</div>
<div *ngIf="__{{item.answer}}__.errors?.pattern">
  {{'Pattern is not match'}}
</div>

I don't know what should i put inside ngIf condition. How can I do it if my template reference variables are comes from array? Is anyone have ideas?

Thanks


Solution

  • Angular creates unique template reference variable for each embedded template so that you can use the same template reference variable name inside ngFor loop:

    <div *ngFor="let item of reusableItems">
        <li class="col-xs-12 pl-lg pr0 pv-sm bd1-bottom">
            <div class="col-xs-4 ph0 pt"> {{item.answerTitle}}</div>
            <div class="col-xs-8">
                <input type="text" name={{item.answer}} ref-answer="ngModel" class="col-sm-12 k-textbox ph0" [(ngModel)]="item.passwordRecoveryAnswer"
                 [pattern]="'[a-z]'" required autocomplete="off" />
                <div *ngIf="answer.errors?.required">
                    {{'Please provide an answer'}}
                </div>
                <div *ngIf="answer.errors?.pattern">
                    {{'Pattern is not match'}}
                </div>
            </div>
        </li>
    </div>
    

    In the code above I use the same name for each input in array

    ref-answer="ngModel" // or you can also use #answer="ngModel