2
votes

I'm customizing angular material select/autocomplete to allow nested dropdowns.

Here, I wanted to have one parent dropdown with many childs. If I expand particular parent dropdown, only childs of that dropdown should expand or collapse. Similarly, checkbox event should be selected in the same scenario.

Here, I got [object object] when I select the dropdowns.

console log is provided to give the values selected/unselected.

Can someone help on this?

STACKBLITZ

<mat-form-field appearance="fill">
  <mat-label>Toppings</mat-label>

  <input type="text" matInput placeholder="Select Users" aria-label="Select Users" matInput [matAutocomplete]="auto" [formControl]="states">
  <mat-autocomplete #auto="matAutocomplete">

    <mat-select-trigger>
      {{states.value ? states.value[0] : ''}}
      <span *ngIf="states.value?.length > 1" class="example-additional-selection">
            (+{{states.value.length - 1}} {{states.value?.length === 2 ? 'other' : 'others'}})
          </span>
    </mat-select-trigger>

    <mat-optgroup *ngFor="let group of stateList">
      <div>
        <mat-checkbox [checked]="group.selected" (change)="toggleParent($event, group)" (click)="$event.stopPropagation()">
          {{group.letter}}
        </mat-checkbox>
        <button mat-button (click)="expandDocumentTypes(group)">
                <mat-icon>keyboard_arrow_down</mat-icon>
              </button>
      </div>
      <mat-option *ngFor="let name of group.names" [value]="name" [ngClass]="isExpandCategory[group.letter] ? 'list-show' : 'list-hide'">
        <mat-checkbox [checked]="group.checked" (change)="toggleSelection($event, name, group)" (click)="$event.stopPropagation()">
          {{name}}
        </mat-checkbox>
      </mat-option>
    </mat-optgroup>

  </mat-autocomplete>
</mat-form-field>



 
export class SelectCustomTriggerExample {
  constructor(private _formBuilder: FormBuilder) {}

  // stateForm: FormGroup = this._formBuilder.group({
  //   stateGroup: '',
  // });
  // toppings = new FormControl();
  isExpandCategory: boolean[] = [];
  toppingList: string[] = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato'];
  stateRecord: any = [];
  states = new FormControl();

  expandDocumentTypes(group: any) {
    console.log("expanding dropdown", group);
    this.isExpandCategory[group.letter] = !this.isExpandCategory[group.letter];
    // expand only selected parent dropdown category with that childs
  }

  toggleSelection(event: any, name: any, group: any) {
    debugger;
    console.log("toggleSelection", name, event.checked, group);
    if (event.checked) {
      console.log("stastateRecordtelist", this.stateRecord);
      this.stateRecord.push(name);
      this.states.setValue(this.stateRecord);
      console.log("toggleselection ", this.states.value);
    } else {
      this.stateRecord = this.stateRecord.filter((x: any) => x !== name);
      console.log("else toggleselection", name, group, this.states.value);
      this.states.setValue(this.states.value.filter((x: any) => x !== name));
      console.log("after filter ", this.states.value);
      //this.states.setValue([]);
    }
  }

  toggleParent(event: any, group: any) {
    debugger;
    group.checked = event.checked;
    console.log("event", event.checked, "group", group, "states value", this.states.value);
    let states = this.states.value;
    states = states ? states : [];
    if (event.checked) {
      states.push(...group.names)
    } else {
      console.log("else", states);
      group.names.forEach((x: string) => {
        if (states.indexOf(x) > -1) {
          states.splice(states.indexOf(x), 1)
        }
      });
    }
    this.states.setValue(states);
    console.log("statesvalue", this.states.value);
    if (!event.checked) {
      this.states.setValue(this.states.value.filter((x: any) => !x.includes(group.names)))
      //this.states.setValue([]);
    }
    console.log("final statesvalue", this.states.value);
  }

  stateList = [{
      "letter": "A",
      "checked": false,
      "names": [{
          "id": 1,
          "type": "Alabama"
        },
        {
          "id": 2,
          "type": "Alaska"
        },
        {
          "id": 3,
          "type": "Arizona"
        },
        {
          "id": 4,
          "type": "Arkansas"
        }
      ]
    },
    {
      "letter": "C",
      "checked": false,
      "names": [{
          "id": 8,
          "type": "California"
        },
        {
          "id": 9,
          "type": "Colorado"
        },
        {
          "id": 10,
          "type": "Connecticut"
        }
      ]
    },
    {
      "letter": "D",
      "checked": false,
      "names": [{
          "id": 18,
          "type": "Delaware"
        },
        {
          "id": 19,
          "type": "Denwer"
        }
      ]
    }
  ];
}

Expected output should look like below

enter image description here

1
Only one group can be selected at one time? - yurzui
no, we should mix and match between dropdowns values. on selecting parent dropdown checkbox, all childs should be selected. upon clicking every checkbox, result should be in array with the values selected - UI_Dev
you can refer this link stackblitz.com/edit/angular-f5mizr-n7gmx5.. and see console logs.. here json response changed.. - UI_Dev
can anyone tell me how to the auto filter here @UI_Dev - Priya
you need to add autocomplete and specify it in matinput like this [matAutocomplete]="auto" - UI_Dev

1 Answers

1
votes

Replace your toggleParent function with below given. You can also find solution in the stackblitz: https://stackblitz.com/edit/angular-f5mizr-final-pxdgby

toggleParent(event: any, group: any) {
  debugger;
  group.checked = event.checked;
  console.log("event", event.checked, "group", group, "states value", this.states.value);
  let states = this.states.value;
  states = states ? states : [];
  if (event.checked) {
    states.push(...group.names.filter((x: any) => !states.includes(x.type)).map((x: any) => x.type))
  } else {
    console.log("else", states);
    group.names.forEach((x: any) => {
      if (states.indexOf(x.type) > -1) {
        states.splice(states.indexOf(x.type), 1)
      }
    });
  }
  this.states.setValue(states);
  console.log("statesvalue", this.states.value);
  if (!event.checked) {
    this.states.setValue(this.states.value.filter((x: any) => !x.includes(group.names)))
    //this.states.setValue([]);
  }
  console.log("final statesvalue", this.states.value);
  this.stateRecord = this.states.value;
}