Update the mat-tigger should be like
<mat-select-trigger>
{{days.value && days.value.length?days.value[0].text:''}}
...
</mat-select-trigger>
Yet corrected in the answer
If we want to see the days selected, we can use a new variable
daysSelected:string="all";
//and is days.valuesChange
this.sub=this.days.valueChanges.subscribe((res:any[])=>{
this.dataSource.filter = res.map((x:any)=>x.value).join(',');
//add this line
this.daysSelected = res.map((x:any)=>x.text).join(',')|| "all";
})
To filter a dataSource we need take account two properties: filter (that is a string) and filterPredicate that is a function with two arguments, the object of the row, and a string, and return true or false.
If we not define the "filterPredicate" the function return true if any property of the object contains the string, but we can define e.g.
filter(data:T,filter:string)
{
return data.symbol==filter; //only if the "symbol" contains the filter
}
Remember that the function filter only execute if filter has value, so we needn't check in the function "filter"
But the first is use a more confortable dayList. If you define
dayList: any[] = [
{value:'Mo',text:'Monday'},
{value:'Tu',text:'Tuesday'},
{value:'We',text:'Wednesday'},
{value:'Th',text:'Thursday'},
{value:'Fr',text:'Friday'},
{value:'Sa',text:'Saturday'},
{value:'Su',text:'Sunday'}
];
Your mat-select like, see that the "value" of day is an array of object
<mat-form-field>
<mat-label>Delivery Day</mat-label>
<mat-select [formControl]="days" multiple>
<mat-select-trigger>
<!--see you show days.value[0].text-->
{{days.value && days.value.length?days.value[0].text:''}}
<span
*ngIf="((days.value?.length || 0) > 1)"
class="example-additional-selection"
>
(+{{(days.value?.length || 0) - 1}} {{days.value?.length === 2 ? 'other'
: 'others'}})
</span>
</mat-select-trigger>
<!--see that the value is the whole "day"-->
<!--e.g. days.valus will be the array [{value:'Mo',text:'Monday'},
{value:'Sa',text:'Saturday']
if you select Monday and Saturday-->
<mat-option *ngFor="let day of dayList" [value]="day"
>{{day.text}}</mat-option
>
</mat-select>
</mat-form-field>
in a subscription to day.valueChange you give value to this.dataSource.filter (don't forget unsubscribe)
See that dataSource.filter is a String.
sub:Subscription;
ngAfterViewInit() {
this.dataSource.sort = this.sort;
this.sub=this.days.valueChanges.subscribe((res:any[])=>{
this.dataSource.filter = res.map((x:any)=>x.value).join(',');
})
}
//to unsubscribe
ngOnDestroy()
{
this.sub && this.sub.unsubscribe()
}
Well the function filter
filter(data:any,filter:string)
{
//data will be, e.g. {position: 10,Name: 'Neon',...DeliveryDay: ['Su', 'Mo']}
//filter wil be, e.g. Su,Tu
const days=filter.split(',') //e.g. days=['Su','Tu']
for (let i=0;i<days.length;i++)
{
if (data.DeliveryDay.includes(days[i])
return true;
}
return false;
}
Well, really we can make more "compact" the function filter
filter(data:any,filter:string)
{
const days=filter.split(',') //e.g. days=['Su','Tu']
let result=false;
days.forEach(x=>result=result||data.DeliveryDay.includes(x))
return result;
}
or even more compact using reduce
filter(data:any,filter:string)
{
const days=filter.split(',') //e.g. days=['Su','Tu']
return days.reduce((a:boolean,b:string)=>a||data.DeliveryDay.includes(b),false)
}
The last piece of the jigsaw is indicate that our dataSource use this filter function
ngAfterViewInit() {
this.dataSource.sort = this.sort;
this.dataSource.filterPredicate=this.filter; //<--this line
this.days.valueChanges.subscribe((res:any[])=>{
this.dataSource.filter = res.map((x:any)=>x.value).join(',');
})
}
Your forked stackblitz in Angular 8
@for{..}and@ifdisableOptionCenteringandpanelClass, e.g.<mat-select [formControl]="days" multiple disableOptionCentering panelClass="days-offset">, and define in styles.css {.days-offset{margin-top:2rem;}