Feature request
To be able to set the mat-option selected property
Currently the mat-option selected property is readonly and you have to programatically select options.
Being able to bind to the selected property would be a cleaner implementation for a user versus having to do it manually, especially in cases where using cascading mat-select with multiple=true (harder to manage)
Angular 4.4.3
Material 2.0.0-beta.11
Windows 10
TypeScript - 2.5.2
All browsers
@djarekg How did you do for options programmatically selection?
If i use select() of MatOptions no selection occurred. If i do this in setTimeout() the option is correctly selected but mat-select has empty text for selected options.
The MatOption has a method, _selectViaInteraction, that will select that option passing true as user input, which will update the UI as well.
The method is not exposed in the d.ts, but if you call option['_selectViaInteraction'](), it will work.
@djarekg Thank you alot! It works!
For me it's giving error:
let optionArr : MatOption[];
optionArr['_selectViaInteraction'](); // error
// error from console :
._selectViaInteraction is not a function
@djarekg can you please make a plunker for it?
@imchaitanya9 You must call MatOption method ['_selectViaInteraction'] on single MatOption not on array.
example
optionArr.forEach((x) => { x['_selectViaInteraction'](); });
I achieved dynamically selected multiple options using ngModel:
<mat-select class="full-width" #mulLoc required placeholder="Locations" multiple [(ngModel)]="resultLocation" name="resultLocation">
<mat-option *ngFor="let l of locations; let i = index" class="multiple-field-box" [value]="l">
{{ l.value }}
</mat-option>
</mat-select>
where
locations = [
{
id : 'USA',
value : 'united states'
},
{
id : 'IND',
value : 'india'
},
{
id : 'INS',
value : 'indonesia'
}
]
resultLocation = [locations[1], locations[2]]
Hope it should help!
@matte00 another approach is to use the select()/deselect()
public methods available in MatOptions.
example:
optionArr.forEach(x => x.select());
I had to set the value
parameter after content checked to avoid changed after checked
errors. Using select()
in the same way didn't work for me, and this updated my label to list checked items as well.
@ViewChild(MatSelect) groupsSelect: MatSelect;
...
ngAfterContentChecked() {
// checks state for selected items i.e. isSelected
// checks the boxes of the selected items in material dropdown by setting its value to an array of the values else an empty array
const selected = this.state.items.length > 0
? this.state.items.filter((val: RefinementListItem) => val.isSelected).map((option: RefinementListItem) => option.value )
: [];
this.groupsSelect.value = selected
}
<mat-form-field>
<mat-select [placeholder]="title" multiple="true" >
<mat-option
*ngFor="let item of items"
[value]="item.value"
(click)="refine($event, item)">
{{ item.label | titlecase }}
</mat-option>
</mat-select>
</mat-form-field>
I could very well be missing the point of this issue report, but it seems that with plain old html options (and angular), one can do something like the following:
<select id="mySelector" formControlName="selectedOption">
<option *ngFor="let optionVal of selectorOptions" [selected]="isSelected(optionVal,partiallyPrefilledFromAccountInfo.value.selectedOption)">{{optionVal}}</option>
</select>
The idea being we have a form that we want to pre-fill based on previously gathered information (to improve the user's experience by shortening their time filling in form fields).
For now, I will try the _selectViaInteraction
solution.
(Again, it's possible I'm missing the point of this thread, I would be happy to post this elsewhere, but the OP seemed close to how I would describe my situation 馃槃 )
Depending on a use-case it is good to know that initializing some default options as selected might not work by simply binding to the ngModel, because default values are different object instances than those in the options array.
Thanks to the support for compareWith
it is possible to set them as selected like so:
[html]
<mat-select [compareWith]="compareFn" ......>
[ts]
compareFn(c1: Object, c2: Object): boolean {
return c1 && c2 ? c1.id === c2.id : c1 === c2;
}
In my case none of the above suggested solutions worked, but once I compared the default selected objects, that come from the parent component, with the objects in the mat-options array, the default options got initialized as selected automatically.
@akolybelnikov, would you mind sharing more code on this?
I can't figure out how to implement this "compareWith" function...
Thanks a lot.
@Jonibigoud it's literally just that. Have a look at the offical Angular docs here.
In Material2 demo-app they have an example of the function with two implementations. It's here.
In my component I have a collection of User objects [people] for the options of mat select. The component receives a collection of selected User objects [users] as Input from previous state. Fair enough, objects in [people] and objects in [users] have different identities and the subset in the multiple select does not initialize with selected checkboxes by default.
So, the magical compareWith
just literally compares objects by some given values and returns true or false, and the checkboxes on the subset of [people] get the status of selected. In my code I decided to go with [(ngModel])
binding:
<mat-form-field>
<mat-select [compareWith]="compareFn" name="users" [(ngModel)]="users" multiple>
<mat-option *ngFor="let person of people" [value]="person">
{{ person.username }}
</mat-option>
</mat-select>
</mat-form-field>
And in the .ts
file I utilize the function from the Angular doc to return true
if two User objects have the same id
:
compareFn(user1: User, user2: User) {
return user1 && user2 ? user1.id === user2.id : user1 === user2;
}
If you have a similar use-case, it might work out-of-the-box.
On the what's-under-the-hood note compareWith
got me going and after a little digging I found out that it is based on a function in Angular2 called looseIdentical
(have a look here in your free time), which in turn derives from the identical
in Dart.js library by Google. It can be found here .
Thank you @akolybelnikov. I understand it now .
I had a similar use-case, now it works like a charm!
I followed @akolybelnikov 's directions and it worked perfectly.
For some weird reason I can only get the first option checked. I made a compareWith function that always returns true.
@akolybelnikov I want to set Mat-Select value from code. And based on assigned drop down value I need to show hide few form fields. I am setting the Mat-Select value from .ts file on initialization. like this
this.myForm.controls.myControl.setValue(this.dd[1]);
This is setting the value in Mat-Select drop down but it is not triggering selectionChange event and hence not able to show/hide other fields. Also reactive form mat-select field is not dirty.
Please suggest if there is a way to achieve this.
@SWGeekPD have you tried, if a dispatchEvent would do that in your case? It's not bound to Angular, but it should work.
Try this.myForm.controls.myControl.updateValueAndValidity()
after setting.
Hello there! I know there were many solutions proposed here and throughout a long, long process of trying to determine how to pre-select your options I came up with a solution that worked for me. My problem was that I couldn't preset values as selected. The way I ended up fixing this was by adding
This is what I'm doing:
<mat-form-field>
<mat-select #thisselect placeholder="Brands" formControlName="brands"
(selectionChange)="selectChanged($event)" multiple required>
<mat-option *ngFor="let brand of brandList; index as i" [value]="i">{{brand.name}}</mat-option>
</mat-select>
</mat-form-field>
@ViewChild('thisselect', {static: false}) thisselect: MatSelect;
ngAfterViewInit() {
setTimeout(() => {
// because the "[value]=" in the html is set to i (index)
// we can set which items we want selected simply by using the index
this.thisselect.value = [0, 2];
}, 1);
}
This is what I'm doing:
HTML
<mat-form-field> <mat-select #thisselect placeholder="Brands" formControlName="brands" (selectionChange)="selectChanged($event)" multiple required> <mat-option *ngFor="let brand of brandList; index as i" [value]="i">{{brand.name}}</mat-option> </mat-select> </mat-form-field>
Typescript
@ViewChild('thisselect', {static: false}) thisselect: MatSelect;
ngAfterViewInit() { setTimeout(() => { // because the "[value]=" in the html is set to i (index) // we can set which items we want selected simply by using the index this.thisselect.value = [0, 2]; }, 1); }
Hi @helzgate,
Is there a way that instead of the index we can select them by the item's value? The index is repeated for each group iteration I believe. So all the groups start from 0, 1, 2 ... It cannot select other groups' items by index.
Most helpful comment
@Jonibigoud it's literally just that. Have a look at the offical Angular docs here.
In Material2 demo-app they have an example of the function with two implementations. It's here.
In my component I have a collection of User objects [people] for the options of mat select. The component receives a collection of selected User objects [users] as Input from previous state. Fair enough, objects in [people] and objects in [users] have different identities and the subset in the multiple select does not initialize with selected checkboxes by default.
So, the magical
compareWith
just literally compares objects by some given values and returns true or false, and the checkboxes on the subset of [people] get the status of selected. In my code I decided to go with[(ngModel])
binding:And in the
.ts
file I utilize the function from the Angular doc to returntrue
if two User objects have the sameid
:If you have a similar use-case, it might work out-of-the-box.
On the what's-under-the-hood note
compareWith
got me going and after a little digging I found out that it is based on a function in Angular2 calledlooseIdentical
(have a look here in your free time), which in turn derives from theidentical
in Dart.js library by Google. It can be found here .