angularangular-materialngforangular-ng-ifng-container

How to get checked checkbox vaule inside ngFor/ngIf?


I have data like so:

 const List: Array<Item> = [
       { id: 1, name: 'somename' }
       ...
]

Then html looks like this:

<ng-container *ngFor="let item of list; let i = index;">
     <div class="grid">

           <mat-checkbox *ngIf="item.id > 4;" #{{item.name}}
                         value="false"
                         type="checkbox">
           </mat-checkbox>

            <mat-form-field *ngIf="item.id <= 4">
                 <input formControlName="{{item.name}}" matInput value="" type="number"/>
            </mat-form-field>
                
            <mat-form-field *ngIf="item.id > 4 && item.name.checked">
                 <input formControlName="{{item.name}}" matInput value="" type="number"/>
            </mat-form-field>
      </div>
</ng-container>

NgFor iterates through the array and creates mat-checkbox's and mat-form-field's.

There is form-field for every item in the array but only some form-field items get checkbox.

Form-field that do not get checkbox are visible at all times.

Form-field that DO get checkbox are ONLY visible after corresponding checkbox is checked.

My problem is how do I get the form-field to be shown after it's checkbox is checked ?

The #{{item.name.checked}} binding isn't working

Edit:

const List: Array<Item> = [
       { id: 1, name: 'somename', class: 'hide' }
       ...
]

<mat-checkbox #checkBoxId class="{{item.class}}"
             type="checkbox">
</mat-checkbox>

SCSS

.hide {
    display: none;
}

Solution

  • When you use a template reference variable inside a *ngFor (or inside a @for) the "scope" is relative to this loop

    What mean this? that you use the "same" variable name (in the code checkBoxId)

    <ng-container *ngFor="let item of list; let i = index;">
         <div class="grid">
               <mat-checkbox *ngIf="item.id > 4;" #checkBoxId
                             value="false"
                             type="checkbox">
               </mat-checkbox>
               <!-- you can use--->
               {{checkboxId.checked}}
    
               <mat-form-field *ngIf="item.id > 4 && checkBoxId.checked">
                     <input formControlName="{{item.name}}" matInput 
                         type="number"/>
                </mat-form-field>
    </ng-container>
              
    

    NOTE: When you use ReactiveFormsControls not use "value", just give value to the formControl.

    Update As it's indicate in comments (thanks for the advise @Dozobus) ther'e a problem when the mat-check is under a *ngIf. we can replace the *ngIf by [style.display]="i<=4?'non':null"

    or use

    <form [formGroup]="form">
      <ng-container *ngFor="let control of  form.controls|keyvalue;let i=index" >
        <mat-form-field *ngIf="items[i].id<=4">
          <input matInput [formControlName]="items[i].name" />
        </mat-form-field><br/>
        <ng-container *ngIf="items[i].id>4">
          <section>
            <mat-checkbox class="example-margin" #checkinId>Check me!</mat-checkbox>
          </section>
          <mat-form-field *ngIf="checkinId.checked">
            <input matInput [formControlName]="items[i].name" />
          </mat-form-field>
        </ng-container>
      </ng-container>
    </form>
    

    NOTE:In submit we need take account this mat-checkbox, we can use some like

    //use ViewChildren to "reach" the checkboxes
    @ViewChildren('checkinId') checkboxes!:QueryList<MatCheckbox>
    
    submit()
    {
        const data={...this.form.value}
        this.items.forEach((x:any,index:number)=>{
           if (x.id>4)
           {
             const checkBox=this.checkboxes.find((_,i:number)=>i==index-4) 
             if (checkBox && !checkBox.checked)
                 data[x.name]=""
           }
        })
        ...do something with "data"
    }
    

    NOTE2: In stackblitz I put diferents ways to mannage the problem using the new @for and @if