Reputation: 3417
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.
I have some bugs here
Case 1.
Select A Parent checkbox, C Parent checkbox, expand both, unselect each values of C and then finally unselecting parent C checkbox will give only the first value of A. Expected should be all values of A as parent A was already selected.
There are some additional bugs also there, hope if case 1 is solved, that will get resolved.
Any help would be highly appreciated.
HTML
<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>
TS Code:
export class SelectCustomTriggerExample {
constructor(private _formBuilder: FormBuilder) {}
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];
}
toggleSelection(event: any, name: any, group: any) {
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 {
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);
}
}
toggleParent(event: any, group: any) {
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) => 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)))
}
console.log("final statesvalue", this.states.value);
}
stateList: StateGroup[] = [{
letter: 'A',
checked: false,
names: ['Alabama', 'Alaska', 'Arizona', 'Arkansas']
}, {
letter: 'C',
checked: false,
names: ['California', 'Colorado', 'Connecticut']
}, {
letter: 'D',
checked: false,
names: ['Delaware']
}, {
letter: 'F',
checked: false,
names: ['Florida']
}, {
letter: 'G',
checked: false,
names: ['Georgia']
}, {
letter: 'H',
checked: false,
names: ['Hawaii']
}, {
letter: 'I',
checked: false,
names: ['Idaho', 'Illinois', 'Indiana', 'Iowa']
}, {
letter: 'K',
checked: false,
names: ['Kansas', 'Kentucky']
}, {
letter: 'L',
checked: false,
names: ['Louisiana']
}, {
letter: 'M',
checked: false,
names: ['Maine', 'Maryland', 'Massachusetts', 'Michigan',
'Minnesota', 'Mississippi', 'Missouri', 'Montana'
]
}, {
letter: 'N',
checked: false,
names: ['Nebraska', 'Nevada', 'New Hampshire', 'New Jersey',
'New Mexico', 'New York', 'North Carolina', 'North Dakota'
]
}, {
letter: 'O',
checked: false,
names: ['Ohio', 'Oklahoma', 'Oregon']
}, {
letter: 'P',
checked: false,
names: ['Pennsylvania']
}, {
letter: 'R',
checked: false,
names: ['Rhode Island']
}, {
letter: 'S',
checked: false,
names: ['South Carolina', 'South Dakota']
}, {
letter: 'T',
checked: false,
names: ['Tennessee', 'Texas']
}, {
letter: 'U',
checked: false,
names: ['Utah']
}, {
letter: 'V',
checked: false,
names: ['Vermont', 'Virginia']
}, {
letter: 'W',
checked: false,
names: ['Washington', 'West Virginia', 'Wisconsin', 'Wyoming']
}];
}
Output should look like below.
Upvotes: 4
Views: 4411
Reputation: 73
maybe this comment won't be your exact answer, but can give you an idea on how to solve it.
Basically your problem is that you are combining diferent components such as mat-autocomplete with a mat-select with multiple selections with a mat-optgroup. And this can very risky and can gives you a lot of headaches. In adition it's is not recommended to do that.
In addition you have a formControl, which is:
[formControl]="states"
inside the input, which is OK, and that's the reasson that you are obtain all the string separated by comma, this is because the value of the formControl.
You can take a look at the documentation of formControls: https://angular.io/guide/reactive-forms
So I highly recommend to change the formControl to the mat-select. (I understand that you will store the value of all the array with subarrays.)
You need to edit the input, to something like that:
<mat-form-field appearance="fill">
<mat-label>Toppings</mat-label>
<!-- <input type="text" matInput placeholder="States Group" formControlName="stateGroup" required [matAutocomplete]="autoGroup">
<mat-autocomplete #autoGroup="matAutocomplete"> -->
<input type="text" matInput placeholder="" aria-label="" matInput [matAutocomplete]="auto" [formControl]="" style="">
<span *ngIf="states.value">
{{states.value ? states.value[0] : ''}}
(+{{states.value.length - 1}} {{states.value?.length === 2 ? 'other' : 'others'}})
</span>
Here is the stackblitz: https://stackblitz.com/edit/angular-f5mizr-wefuik
Upvotes: 0
Reputation: 2864
Find you answer here:: https://stackblitz.com/edit/angular-f5mizr-n7gmx5
This will pass your test case 1. And I found one more case
Select and Unselect any child element multiple time it will repeat duplicate selected value.
This case also fixed in my given stackblitz.
Upvotes: 1