Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

md-select-option selected not getting selected on angular reactive form #5590

Open
asegurala opened this issue Apr 18, 2024 · 4 comments
Open

Comments

@asegurala
Copy link

What is affected?

Component

Description

When I try to use md-outlined-select with Reactive Forms on Angular 17

Reproduction

In Angular, I have a form with Reactive Forms, it has a couple of Inputs, Selects, and a Submit button to perform a search. When navigating to another route and returning to my search page, the input fields do show the previously entered values, but this does not happen with the Selects.

However, if I use the Selects with ngModel using Template-driven forms, all the select fields work correctly.

Selects doesn't works with Reactive Forms on Angular 17.x:

Deporte
@for (sport of (sports$ | async); track sport.id) {
{{ sport.name }}
}

Workaround

Using Template-drive Forms works:

<md-outlined-select [(ngModel)]="sportId" ngDefaultControl>
<md-select-option *ngIf="!sport" disabled value="">

Deporte


@for (sport of (sports$ | async); track sport.id) {

{{ sport.name }}


}

Is this a regression?

No or unsure. This never worked, or I haven't tried before.

Affected versions

@material/web@1.4.x / and nightly

Browser/OS/Node environment

Brave Version 1.64.122 Chromium: 123.0.6312.122 (Official Build) (64-bit)
Chrome / Firefox on Arch Linux 6.8

Node 18.18.2
Angular 17.0

@austinw-fineart
Copy link

In my case, the issue appears to be caused by dynamically populating md-select-option(s) causing the select to appear blank even though the option is selected when you open the menu. The weird thing though is that sometimes the select is blank and sometimes the select isn't blank.

@Vyachean
Copy link

Vyachean commented May 4, 2024

I was able to reproduce this without frameworks. @austinw-fineart guess is correct.
the problem is not specific to Angular, I got the problem when working with Vue.

@davie-robertson
Copy link
Contributor

davie-robertson commented May 29, 2024

I also had a similar issue when setting the selected value without any framework, discord discussion and workaround here

@jeremylazarus
Copy link

jeremylazarus commented Sep 15, 2024

I can't view the discord discussion linked above, but I did look at the code sample from @Vyachean and I have a workaround.

I personally ran into this bug while building a reactive component using the Lit framework. From what I could tell, there were two issues experienced in the following code:

connectedCallback() {
  super.connectedCallback();
  // Note that items are loaded asynchronously, which results in this bug.
  this.items = this.loadItems().then(items => this.items = items);
}

render() {
  return html`
    <md-outlined-select>
      ${this.items.map((item, idx) => html`
         <md-select-option value=${item.id} ?selected=${item.id === 2}>
           ${item.name}
         </md-select-option>
      `)}
    </md-outlined-select>
  `;
}

Within the md-select component, a private method "updateValueAndDisplayText()" sets the default selected display value. This gets called during the firstUpdated lifecycle event, which is why the component works properly when the md-select-options are rendered at the same time as the md-select component.

When the options are loaded after the initial render, updateValueAndDisplayText() is never called. My first attempt at fixing this was simply to call "reset()" on the md-select component after my options are loaded. reset() invokes updateValueAndDisplayText() and is exposed publicly.

This may work in some cases, such as the linked workaround, but I ran into a second issue. The "displayText" property for md-select-option wasn't being set with the content of the default slot. This caused the text to still not render as the default selected display value. I fixed this by manually setting displayText when rendering the component.

So in the end, here's what I ended up with in my component:

connectedCallback() {
  super.connectedCallback();
  this.items = this.loadItems().then(items => this.items = items);
}

render() {
  return html`
    <md-outlined-select>
      ${this.items.map((item, idx) => html`
         <md-select-option value=${item.id} ?selected=${item.id === 2} .displayText=${item.name}>
           ${item.name}
         </md-select-option>
      `)}
    </md-outlined-select>
  `;
}

updated() {
  const sel = this.shadowRoot!.querySelector('md-outlined-select');
  sel?.reset();
}

Fixing this bug will involve reworking the lifecycle of this component. Dynamically adding a md-select-option to the md-select component doesn't trigger a lifecycle event in the md-select component as far as I could tell, so it may not be a simple fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
5 participants