Reputation: 777
I am trying to display a list of chips with predefined values to a user, and let user select some of them. My goal is selection of multiple chips by clicking, with reaction in accordance.
The problem is, that not a single event is emitted.
What I am doing wrong?
manage-roles.component.html
<mat-chip-list [selectable]="true" [multiple]="true"
(change)="onChange($event)">
<mat-chip *ngFor="let role of possibleRoles"
[selectable]="true" (selectionChange)="onChipSelect($event)">
{{role}}
</mat-chip>
</mat-chip-list>
manage-roles.component.html
@Component({
selector: 'hr-manage-roles',
templateUrl: './manage-roles.component.html'
})
export class ManageRolesComponent implements AfterViewInit {
@ViewChild(MatChipList) chipList: MatChipList;
possibleRoles: string[] = Roles; // some const
ngAfterViewInit(): void {
this.chipList.chipSelectionChanges.subscribe(change => {
console.log(change); // not fires
})
}
onChange(change: MatChipListChange){
console.log(change); // not fires
}
onChipSelect(change: MatChipSelectionChange) {
console.log(change); // not fires
}
}
package.json
"dependencies": {
"@angular/animations": "^5.0.0",
"@angular/cdk": "^5.0.0",
"@angular/common": "^5.1.0",
"@angular/compiler": "^5.1.0",
"@angular/core": "^5.1.0",
"@angular/flex-layout": "^2.0.0-beta.10-4905443",
"@angular/forms": "^5.0.0",
"@angular/http": "^5.1.0",
"@angular/material": "^5.0.0",
"@angular/platform-browser": "^5.0.2",
"@angular/platform-browser-dynamic": "^5.0.0",
"@angular/router": "^5.0.0",
"core-js": "^2.4.1",
"rxjs": "^5.5.2",
"zone.js": "^0.8.14"
},
"devDependencies": {
"@angular/cli": "1.5.2",
"@angular/compiler-cli": "^5.0.0",
"@angular/language-service": "^5.0.0",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "~3.2.0",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~3.2.0",
"tslint": "~5.7.0",
"typescript": "~2.4.2"
}
Upvotes: 5
Views: 15045
Reputation: 419
There are 2 solutions if you want to use (change)
on mat-chip-list
:
selectViaInteraction()
, Stackblitz<mat-chip-list (change)="onChange($event)">
<mat-chip #chipRef="matChip" (click)="chipRef.selectViaInteraction()">
SOME TEXT HERE
</mat-chip>
</mat-chip-list>
toggleSelected(true)
<mat-chip-list (change)="onChange($event)">
<mat-chip #chipRef="matChip" (click)="chipRef.toggleSelected(true)">
SOME TEXT HERE
</mat-chip>
</mat-chip-list>
For anyone who is curious about 'why' the change
event is not fired in your code. Here below is the explanation:
From on MatChipList's source code, we can see the change
event emitter on MatChipList
will be triggered only if MatChipList received an MatChipSelectionChange
with isUserInput
set to true
from its descendent MatChip.
784 if (event.isUserInput) {
785 this._propagateChanges();
786 }
And if you take a look at the MatChip source code you will find out that the isUserInput
on MatChipSelectionChange
will be set to true
only when you call MatChip's toggleSelected(true)
or selectViaInteraction()
.
369 selectViaInteraction(): void {
370 if (!this._selected) {
371 this._selected = true;
372 this._dispatchSelectionChange(true);
373 this._changeDetectorRef.markForCheck();
374 }
375 }
376
377 /** Toggles the current selected state of this chip. */
378 toggleSelected(isUserInput: boolean = false): boolean {
379 this._selected = !this.selected;
380 this._dispatchSelectionChange(isUserInput);
381 this._changeDetectorRef.markForCheck();
382 return this.selected;
383 }
Upvotes: 0
Reputation: 2638
The MatChip selection has to be handled manually... so in order selectionChange emit a value you have to manually change mat-chip component selected state. You can change it in two ways:
Bind a selected value to matChip component like this, you can modify that Input selected value for example in the click event function callback: ( in this example I would have a property selected on role object ):
<mat-chip *ngFor="let role of possibleRoles" [selected]="role.selected"
(selectionChange)="onChipSelect($event)" (click)="roleClicked(role.id)">
{{role}}
</mat-chip>
Doing like this in your roleClicked function you would have to calculate the new state of the roles selected property.
Get the reference to the MatChip component and set Selected imperatively. I would not post an example of this because I don't recommend this options, but you can use it in some cases...
Hope this helps.
Upvotes: 2
Reputation: 5762
Tried using (click)
instead of selectionChange event and it worked. I had several similar issues while working with material components. Anyway, if you are happy with just the data on the Chip and not the actual component, you can achieve what you want doing this:
<mat-chip-list class="mat-chip-list-stacked" [selectable]="true" [multiple]="true">
<mat-chip *ngFor="let chip of availableColors" (click)="selectMe(chip)">
{{chip.name}}
</mat-chip>
</mat-chip-list>
public selectMe(event: any) {
console.log(event);
}
Demo here
Upvotes: 8