cheshire
cheshire

Reputation: 1159

multiple select form two-way binding

I have a multiple select form:

<mat-form-field>
    <mat-label>Toppings</mat-label>

    <mat-select  [(value)]="selected"  multiple>
        <mat-option *ngFor="let topping of toppings" [value]="topping">{{topping.value}}</mat-option>
    </mat-select>

</mat-form-field>
<p>You selected: {{selected}}</p>

I want to display options that user selected under the form with <p>You selected: {{selected}}</p>, but if I do it this way I get when I select 3 toppings:

   You Selected: [object Object],[object Object],[object Object]

Now I tried <p>You selected: {{selected?.value}}</p> I don't get any entry.

The only solution I have found so far is: <p>You selected: {{selected | json}}</p> but I do not want whole json object just value property.

How do I get it to display:

You selected: option1, option2, option3

?

Upvotes: 0

Views: 3307

Answers (3)

cerkiner
cerkiner

Reputation: 1956

Printing "[object, object]" means you are trying to use an object as a string.

toppings is an array of objects. You are looping through this array with let topping of toppings and assigning an object to topping.

{{topping.value}} prints the string in the .value property of topping object but you assigned back the whole object in [value]="topping".

This way selected becomes an array of objects although you are only seeing strings while clicking on options.

Two ways to achieve what you want;

- Pass string from options

<mat-form-field>
    <mat-label>Toppings</mat-label>

    <mat-select  [(value)]="selected"  multiple>
        <mat-option *ngFor="let topping of toppings" [value]="topping.value">{{topping.value}}</mat-option>
    </mat-select>

</mat-form-field>
<p>You selected: {{selected}}</p>

- Loop through selected array

<mat-form-field>
    <mat-label>Toppings</mat-label>

    <mat-select  [(value)]="selected"  multiple>
        <mat-option *ngFor="let topping of toppings" [value]="topping">{{topping.value}}</mat-option>
    </mat-select>

</mat-form-field>
<p>You selected: 
    <span *ngFor="let s of selected; let f = first; let l = last;">
        {{s.value}}
        <span *ngIf="!(f && l) && !l">,</span>
    </span>
</p>

I hope this helps you clarify angular templating and data binding.

Upvotes: 2

Aakash Garg
Aakash Garg

Reputation: 10979

Try Changing your HTML to :- 

<mat-form-field>
    <mat-label>Toppings</mat-label>

    <mat-select  [(value)]="selected"  multiple>
        <mat-option *ngFor="let topping of toppings" [value]="topping">{{topping.value}}</mat-option>
    </mat-select>

</mat-form-field>
<p>You selected: {{selected | json}}</p>

Upvotes: 1

Chris Danna
Chris Danna

Reputation: 1264

You can either make a new property on the component to bind in the template, or make a new pipe to display comma-delimited items.

Without a pipe:

get displaySelections(): string {
  return this.selections.map(s => s.value).join(', ');
}
<p>You selected: {{displaySelections}}</p>

With a pipe, you can re-use in other components as well, and you don't need to add the getter:

@Pipe({
  name: 'join'
})
export class JoinPipe implements PipeTransform {
  transform(value: {value: any}[]): string {
    return value.map(v => v.value).join(', ');
  }
}
<p>You selected: {{ selections | join }}</p>

Upvotes: 0

Related Questions