1

I have an array values and the values is seen on Chrome Debugger as shown below:

value: Array(3)
    0: EmployeeDto {id: 1, name: "John"}
    1: EmployeeDto {id: 2, name: "Marry"}
    2: EmployeeDto {id: 3, name: "Thomson"}
length: 3

And I assign these values to the related variable as shown below:

employees =  this.employees ? this.employees : [];

However, although I pass these values by id-name pairs to the mat-select multiple selection, it does not display these value. But, when I use selected values on the opened window, they are retrieved by their id values and the record can be updated using these id values.

The problem is related to passing these values in a wrong format I think, but as far as I know, the id-value pairs should be passed so that id is used to keep values (for submit) and name is used to display these values. On the other hand, if I pass only name values as array [...] they are diaplayed without any problem. So, how should I display these values on mat-select multiple selection?

8
  • Please can you paste your whole code here ?so that it's easy to debug Commented Dec 13, 2020 at 17:28
  • it's not easy to debug without code like @Sakshi says, it's better if u could reproduce in the stackblitz. I guess the data isn't available when the component is rendered, so your mat-select receive actually [] Commented Dec 13, 2020 at 17:40
  • thanks for reply, but the data is available before rendering. I just wondered if I should bind as object array containing is and name values as shown above or pass name values by mapping the values above. It will helps me really if you also give an example. Commented Dec 13, 2020 at 17:46
  • the following example seems to be similar to my example, but I am not sure where is the mistake in my approach? stackblitz.com/edit/… Commented Dec 13, 2020 at 17:47
  • I'm not prety suere how is your array, but it's looks like each element of your array is an object that each object has with two properties, use employees = this.employees ? this.employees.map(x=>x.EmployeeDto) : []; Commented Dec 13, 2020 at 18:15

1 Answer 1

3

Update incluying services*

In general, in a mat-select multiple that is feeded whith an array of object we need take account two things 1.- the result (in a FormControl or in a variable using [(ngModel)]) is an array 2.- we general want to store in the variable or in the form control, one property of the object and show anohter

So, a tipical

  toppingList: any[] = [
    {id: 1, name: "John"},
    {id: 2, name: "Marry"},
    {id: 3, name: "Thomson"}];

need a getter

  toppings = new FormControl();

  get toppingsName()
  {
    return this.toppings.value?
              this.toppingList.filter(t=>this.toppings.value.indexOf(t.id)>=0)
              .map(x=>x.name):
              null
  }

If we has a service that return an array we can write

this.dataService.getToppings1().subscribe((res:number[])=>{
     this.toppings.setValue(res)
})
    <mat-form-field appearance="fill">
      <mat-label>Toppings</mat-label>
      <mat-select [formControl]="toppings" multiple>
        <mat-select-trigger>
          {{toppingsName}}
        </mat-select-trigger>
        <mat-option *ngFor="let topping of toppingList" [value]="topping.id">{{topping.name}}</mat-option>
      </mat-select>
    </mat-form-field>

Or using ngModel

  value:any=null;
  get toppingsNameValue()
  {
    return this.value?this.toppingList.filter(t=>this.value.indexOf(t.id)>=0).map(x=>x.name):null
  }

If we has a service that return an string separate by commas with the toppings choose we can do -see that first make a spit, but we need transform this array of string in array of numbers-

this.dataService.getToppings2().subscribe((res:string)=>{
     this.value=res.split(',').map(x=>+x)
})
    <mat-form-field appearance="fill">
      <mat-label>Toppings</mat-label>
      <mat-select [(ngModel)]="value" multiple>
        <mat-select-trigger>
          {{toppingsNameValue}}
        </mat-select-trigger>
        <mat-option *ngFor="let topping of toppingList" [value]="topping.id">{{topping.name}}</mat-option>
      </mat-select>
    </mat-form-field>

Well, we can also that we want an array of object (it's not ussual, remember that always can get the value simply using this.toppingList.filter(t=>this.toppings.value.indexOf(t.id)>=0

We can do

  toppingsObject = new FormControl();
  get toppingsObjectName()
  {
    return this.toppingsObject.value?this.toppingsObject.value.map((x:any)=>x.name):null
  }

Now, our service is going to return an array of object. But we can not use directly an object to feed our control. We need a "compare function". Its only a function that has two arguments. We return true if we considered the two object equals. Some like

 compareFn(a:any,b:any){
   if (a.id==b.id) 
     return true
   else
     return false
 }
 

Well, normally we abreviature and write this function like

 compareFn=(a:any,b:any)=>a.id==b.id

Now our subscription to the service is like

this.dataService.getToppings3().subscribe((res:any[])=>{
     this.toppingsObject.setValue(res)
})
    <mat-form-field appearance="fill">
      <mat-label>Toppings</mat-label>
      <!--see how use the compareFn-->
      <mat-select [formControl]="toppingsObject" multiple [compareWith]="compareFn">
        <mat-select-trigger>
          {{toppingsObjectName}}
        </mat-select-trigger>
        <mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping.name}}</mat-option>
      </mat-select>
    </mat-form-field>

See that in this case [value] is the own "topping"

NOTE: In general we store the data in a dbs as string

In the stackblitz I put the three cases

Sign up to request clarification or add additional context in comments.

10 Comments

It is exactly perfect in a word, thank you very much for these wonderful explanations and demo code. I learned many things about multple select wit the help of your detailed explanataions ;) Voted up!
The only thing that I could not understand exactly is this.toppingsObject.value.map((x: any) => x.name) line. In the third example we use object as [value] instead of id, but how this.toppingsObject.value.map((x: any) => x.name) passes name parameter only I think. Hpw the id parameters are retrieved in html part of this case [value] is the own "topping"?
toppingsObjectName is what we show in the edit. this.toppingsObject is the formControl, this.toppingsObject.value is the value and is an array of object, maptransform the array of object in an array of string. map create a new array in each element of the new array is "something" relationate with the original array. "each" element of the array is only the property "name" of the original
Yes, but the point I mentioned is that: this.toppingList.map(x => console.log(x.name)); returns only names. But in this case when we only have name fields, how can we pass id of them when submitting the form?
The second question is I think [value] parameter is used in order to display the select list values that was previously recorded. So, in that case what is the difference between [value]="topping" and [value]="topping.id"?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.