angularangular-materialmat-selectmat-list

How to display a select component underneath a checked checkbox in a selection list in Angular?


I'm trying to display a select item underneath a checkbox in Angular, which is included in a selection list:

<mat-selection-list>
    <mat-list-option 
        *ngFor="let checkbox of checkboxes" 
        color="primary" 
        checkboxPosition="before"
        [value]="checkbox" 
        [selected]="isCheckboxChecked(checkbox)" 
        (click)="changeCheckboxState(checkbox)"
    >
        <span class="extense-text">{{ checkbox.label }}</span>

        <div *ngIf="checkbox.label === 'Checkbox 3'">
        <mat-form-field>
            <mat-label>Choose an option</mat-label>
            <mat-select [(value)]="selectedOption" (selectionChange)="selectOption($event.value)">
                <mat-option *ngFor="let option of options" [value]="option">
                    {{option}}
                </mat-option>
            </mat-select>
        </mat-form-field>
        </div>
    </mat-list-option>
</mat-selection-list>

However, this is how it looks: Wrong behaviour

I can also set the select component at the bottom, but it doesn't seem natural to me:

<mat-selection-list>
    <mat-list-option 
        *ngFor="let checkbox of checkboxes" 
        color="primary" 
        checkboxPosition="before"
        [value]="checkbox" 
        [selected]="isCheckboxChecked(checkbox)" 
        (click)="changeCheckboxState(checkbox)"
    >
        <span class="extense-text">{{ checkbox.label }}</span>
    </mat-list-option>
</mat-selection-list>

<div *ngFor="let checkbox of checkboxes">
    <div *ngIf="checkbox.label === 'Checkbox 3'">
        <mat-form-field>
            <mat-label>Choose an option</mat-label>
            <mat-select [(value)]="selectedOption" (selectionChange)="selectOption($event.value)">
                <mat-option *ngFor="let option of options" [value]="option">
                    {{option}}
                </mat-option>
            </mat-select>
        </mat-form-field>
    </div>
</div>

Not what I pretend to do

Is there any way to do what I'm looking for? Thanks!


Solution

  • We can use the below CSS, to make the options take the height of the children.

    .custom-list-select {
      mat-list-option {
        height: 100% !important;
      }
    }
    

    Also we can use the <mat-form-field (click)="$event.stopImmediatePropagation()"> from bubbling up the events to trigger the checkbox selection, when the select is operated.

    Full Code:

    HTML:

    <mat-selection-list class="custom-list-select">
      <mat-list-option
        *ngFor="let checkbox of checkboxes"
        color="primary"
        checkboxPosition="before"
        [value]="checkbox"
        [selected]="isCheckboxChecked(checkbox)"
        (click)="changeCheckboxState(checkbox)"
      >
        <span class="extense-text">{{ checkbox.label }}</span>
    
        <div *ngIf="checkbox.label === 'Checkbox 3'">
          <mat-form-field (click)="$event.stopImmediatePropagation()">
            <mat-label>Choose an option</mat-label>
            <mat-select
              [(value)]="selectedOption"
              (selectionChange)="selectOption($event.value)"
            >
              <mat-option *ngFor="let option of options" [value]="option">
                {{option}}
              </mat-option>
            </mat-select>
          </mat-form-field>
        </div>
      </mat-list-option>
    </mat-selection-list>
    

    TS:

    import { Component } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { MatListModule } from '@angular/material/list';
    import { MatFormFieldModule } from '@angular/material/form-field';
    import { MatSelectModule } from '@angular/material/select';
    
    /**
     * @title Basic list
     */
    @Component({
      selector: 'list-overview-example',
      templateUrl: 'list-overview-example.html',
      standalone: true,
      imports: [MatListModule, MatFormFieldModule, MatSelectModule, CommonModule],
    })
    export class ListOverviewExample {
      options = ['asdf', 'qwer', 'zxcv'];
      checkboxes = [
        { label: 'Checkbox 1' },
        { label: 'Checkbox 2' },
        { label: 'Checkbox 3' },
        { label: 'Checkbox 4' },
        { label: 'Checkbox 5' },
        { label: 'Checkbox 6' },
        { label: 'Checkbox 7' },
      ];
      selectedOption = '';
    
      isCheckboxChecked(item: any) {
        return item.checked;
      }
    
      changeCheckboxState(item: any) {
        item.checked = !item.checked;
      }
    
      selectOption(value: any) {}
    }
    

    Stackblitz Demo