6

I'm trying to populate a material select dropdown with values from a remote API service. I keep getting a null or undefined value at the component.

This is for Angular 7 using the MEAN stack and Angular Material. I've tried compareWith function and logging the values. I noticed that the component is always loading its value first which is null, then the API service which has values.

<mat-form-field>
    <mat-select formControlName="company"  placeholder="Select 
Company" [(value)]="selectedCompany" [compareWith]="compareFn">
        <mat-option *ngFor="let lC of loadedCompanies" 
 [value]="lC.id">
          {{lC.name}}
        </mat-option>
    </mat-select>
</mat-form-field>

ngOnInit() {
  this.authStatusSub = this.authService
  .getAuthStatusListener()
  .subscribe(authStatus => {
      this.isLoading = false;
  });

  this.form = new FormGroup({
      id: new FormControl(null),
      company: new FormControl(this.loadedCompanies)
  });

  this.companyService.getCompanyList();
  this.companySub = this.companyService
  .getcompanyUpdateListener()
  .subscribe((companyData: {companies: Company[]}) => {
    this.isLoading = false;
    this.loadedCompanies =  companyData.companies;
  });
}

compareFn(c1: Company, c2: Company): boolean {
  return c1 && c2 ? c1.id === c2.id : c1 === c2;
}

I would expect the values to load from the observable and populate the select input before loading the component.

wentjun
  • 40,384
  • 10
  • 95
  • 107
Badger 29
  • 113
  • 3
  • 12
  • 1
    Hold on a second.. Is `this.companyService.getCompanyList()` supposed to be the API call that populates the `this.loadedCompanies`? – wentjun Apr 04 '19 at 06:28

1 Answers1

8

You can add an *ngIf to the parent container such that the mat-select component will not be loaded until the observable has been subscribed and loadedCompanies has been assigned.

 <mat-form-field *ngIf = "loadedCompanies">
   <mat-select formControlName="company"  placeholder="Select 
Company" [(value)]="selectedCompany" [compareWith]="compareFn">
     <mat-option *ngFor="let lC of loadedCompanies" 
 [value]="lC.id">
       {{lC.name}}
     </mat-option>
  </mat-select>
</mat-form-field>

The FormControl company should be set with an initial value of null, and not the entire loadedCompanies array.

this.form = new FormGroup({
  id: new FormControl(null),
  company: new FormControl(null)
});

This is how you should populate your loadedCompanies array.

loadedCompanies: Company[];

ngOnInit() {
  .
  .
  // other lines of code before this
  this.companyService.getCompanyList().subscribe(companyData => {
    this.loadedCompanies = companyData.companies;
  });
}
wentjun
  • 40,384
  • 10
  • 95
  • 107
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/191223/discussion-on-answer-by-wentjun-how-to-populate-material-select-dropdown-from-re). – Samuel Liew Apr 04 '19 at 10:11
  • 1
    Thanks! It worked as you stated. Had to remove the companyUpdateListener and also remove the subscribe method from the service. – Badger 29 Apr 04 '19 at 10:41