ngModel doesn't display the value of an object in mat-select
Asked Answered
P

2

6

I have a company class, it has an headquarter's address field. The address is an interface, it has an another object, country, which is an another interface. In my database I store all the countries. I have a view for editing a selected company, there I can set or change the headquarter's address and I created a mat-select for the countries:

<mat-select [(ngModel)]="company.headquarter.country">
    <mat-option *ngFor="let country of companyService.countries" [value]="country">
        {{country.name}}
    </mat-option>
</mat-select>

This code save the selected country to the headquarter's country field, but if I want to edit the same company the mat-select doesn't display the actual value. how can I solve this problem?

Edited:

If I change the ngModel to company.headquarter.country.id and the [value] to country.id, then it works fine, but to store the country's code or name I have to write a method, which will find the country by the id in the companyService.countries array and set this country to the company.headquarter.country's field. So it is not a good solution.

Protasis answered 26/3, 2018 at 8:51 Comment(2)
Is it ChangeDetection issue ? Your main component is in OnPush detection strategy ? if yes, please check angular.io/api/core/ChangeDetectorRef – Humility
Did you ever find a good solution to this? I've also gone the route to have a method figure out what the id v value should be once the selection is completed since binding the value to the Id and displaying the value does not work. – Applegate
M
11

This code save the selected country to the headquarter's country field, but if I want to edit the same company the mat-select doesn't display the actual value. how can I solve this problem?

The problem is when you mat-select compares two object, their references can be different. Use compare function to compare your object by some mark like id.

To customize the default option comparison algorithm, supports compareWith input. compareWith takes a function which has two arguments: option1 and option2. If compareWith is given, Angular selects option by the return value of the function.

Template:

 <mat-form-field>
              <mat-select [(value)]="contract.company"
                          panelClass="example-panel-dark-blue"
                          [compareWith]="helper.compareById">

                <mat-option *ngFor="let cust of customers"
                            [value]="cust"> {{cust.title}}
                </mat-option>
              </mat-select>
  </mat-form-field>

Code:

 compareById(f1: Common.Item, f2: Common.Item): boolean {
     return f1 && f2 && f1.id === f2.id;
 }

Official Doc

Mechanic answered 26/3, 2018 at 10:45 Comment(1)
Cool! Happy to help πŸ‘ – Mechanic
E
1

Change [(ngModel)] to [(value)].

<mat-select [(value)]="company.headquarter.country"> 
  <mat-option *ngFor="let country of companyService.countries" [value]="country"> {{country.name}}
   </mat-option>
</mat-select>
Epigoni answered 26/3, 2018 at 9:19 Comment(5)
Same problem. With this solution saving the country to the company.headquarter.country is working, but when I want to edit, the mat-select doesn't display the current value. – Protasis
Is your mat-select inside mat-form-field? – Epigoni
run.stackblitz.com/api/angular/… – Epigoni
Yes, it is inside a mat-form-field. The link doesn't work! – Protasis
It also might be an object identity problem. Remember that in js { hello: 'world' } !== { hello: 'world } so I would advise binding the select to a scalar value. – Epigoni

© 2022 - 2024 β€” McMap. All rights reserved.