0

I'm working on a project with Angular 5 using Clarity Design as a CSS framework.

On a select I'm binding its options dynamically and a weird thing happens when binding a new item.

Basically the new item gets added to the DB, and inside the subscription callback is where the binding gets done. When that happens the select looks like no option has been selected, the binding is being made correctly but that visual aspect is what I'm stuck with now.

Here's how the select is like on the markup:

<div class="row">
    <div class="col-xs-12">
      <div
        class="select"
        [class.disabled]="contextResources.length < 1">
        <select
          [disabled]="contextResources.length < 1"
          (change)="emitSelectedResource(optionSelected)"
          [(ngModel)]="optionSelected">
          <option *ngIf="contextResources.length < 1">Agrega un {{ context.name | lowercase}} nuevo</option>
          <option
            *ngFor="let contextResource of contextResources"
            [ngValue]="contextResource">
          {{ contextResource.name }}</option>
        </select>
      </div>
    </div>
  </div>

And the component method:

addResource(): void {
    this.isLoading = true;
    this.resourceAdded = false;
    this.resourceError = false;

    let parentId = this.previousResource ? this.previousResource.id : null;

    this.resourceServices[this.currentStep].create({'newResource': this.newResource}, parentId)
      .finally(() => this.isLoading = false)
      .subscribe(
        response => {
          this.contextResources.push(response.json().newResource as ContextResource);

          if(this.contextResources.length == 1)
            this.emitSelectedResource(this.contextResources[0]);

          this.newResource = '';
          this.resourceAdded = true;
          this.emptyResources.emit(false);
        },
        (error: AppError) => {
          if(error instanceof BadRequestError)
            return this.resourceError = true;

          throw error; 
        }
      );
  }

This is how the select looks like with some options, all normal:

enter image description here

Now after adding a new item:

enter image description here

And if we take a look inside the list:

enter image description here

Is the a way to prevent this behavior?

Fer VT
  • 500
  • 1
  • 8
  • 25

1 Answers1

3

Yes, the contextResources are brand new objects every time, and select checks the selected one based on reference equality by default.

The answer is to use the [compareWith] input, as explained here: https://angular.io/api/forms/SelectControlValueAccessor#caveat-option-selection

<select [compareWith]="compareFn"  [(ngModel)]="selectedCountries">
    <option *ngFor="let country of countries" [ngValue]="country">
        {{country.name}}
    </option>
</select>
compareFn(c1: Country, c2: Country): boolean {
    return c1 && c2 ? c1.id === c2.id : c1 === c2;
}
Eudes
  • 1,521
  • 9
  • 17
  • I added what is showed in your answer and modified the compareFn function in my component to "return c1.id === c2.id" but its giving me the following error "Cannot read property 'id' of undefined". Maybe I need to make my array an observable? – Fer VT Feb 28 '18 at 03:11
  • The whole point of the `c1 && c2` part is to check for `undefined` `c1` or `c2`. If you remove this, you will hit the exact error you posted. – Eudes Feb 28 '18 at 13:21
  • I tried to implement it that way based on a couple of examples that I saw. That makes sense, but I'm getting the same behavior. The thing that I notice is that if I manually select one of the options and then add another one, the list doesn't "go away" anymore. It disappears only if I add one before choosing an option manually. – Fer VT Feb 28 '18 at 15:37
  • Well I actually solved that last part by programmatically choosing a default value. It's working fine now :) – Fer VT Feb 28 '18 at 17:07