1

I'm trying to use a material select component that gets its values through an Observable with async pipe.

template:

<mat-form-field>
  <mat-select
       value="selectedOption$ | async"
       (selectionChange)="onSelectionChange($event.value)">
     @for (option of (optionList$ | async) ?? []; track option) {
       <mat-option [value]="option">{{option.name}}</mat-option>
     }
  </mat-select>
</mat-form-field>

typescript:

...
export class SomeContainer {
  private readonly someService = inject(SomeService);

  readonly selectedOption$;

  readonly optionList$;

  constructor() {
    this.selectedOption$ = this.someService.fetchOption$(
      this.someService.getCurrentOptionId$(),
    );

    this.optionList$ = this.someService.getOptionList$();
  }

  onSelectionChange(option: Option): void {
    this.someService.setSavedOption(option.optionId);
  }
}

And in the service class, I just save the selected option into localstorage, as well as fetch the saved options from localstorage and fetch it. I'm able to see the list of options in the component as well as change select them, but the initial saved option doesn't display, and it's just an empty box. I've tried using behaviorsubject with a set initial value as well instead of simply an Observable, but the initial value is still not displayed.

I'm not sure what the issue is here, I'm expecting to see an initial option selected for the component, but it's not being shown. Any help would be appreciated.

1
  • Does selectedOption$ emit the full object or just the value? It should be just the value, not the full object. StackBlitz Commented Apr 13 at 21:10

1 Answer 1

0

Currently the value binds selectedOption$ | async as string instead of actual value.

You should use [value] or [ngModel] (one-way binding).

Besides, as you are attempting to bind the value with object, you should also implement the [compareWith] to the <mat-select> to ensure the previous selected object is bind correctly.

<mat-form-field>
  <mat-select
    [value]="selectedOption$ | async"
    (selectionChange)="onSelectionChange($event.value)"
    [compareWith]="compare">
    @for (option of (optionList$ | async) ?? []; track option) {
      <mat-option [value]="option">{{option.name}}</mat-option>
    }
  </mat-select>
</mat-form-field>
compare(device1: any, device2: any) {
  return device1?.deviceId === device2?.deviceId;
}

Demo @ StackBlitz

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

8 Comments

At first I was using [value] instead of just value, but what would happen is that it is still initially empty, and after selecting a different option, the display would still be empty, and I had to select that option again for the option to be actually displayed as selected.
I wonder if it's something wrong with the way I set up the observables then.
Perhaps can you create a StackBlitz demo to reproduce it?
stackblitz.com/edit/… Hmmm, this is very weird. In StackBlitz it is working as intended, but where I'm running this, I get the issue. If you have any ideas, feel free to mention. But I'll take a look at this and keep this post updated.
Thanks! [compareWith] resolved the issue.
|

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.