components icon indicating copy to clipboard operation
components copied to clipboard

mat-select does not display default (null) option text in mat-option

Open zolakt opened this issue 2 years ago • 28 comments

Is this a regression?

  • [ ] Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

I'm reposting this issue again: https://github.com/angular/components/issues/6466

since you closed it without providing any reasonable workaround or an explanation why you chose to implement this super weird, opinionated, behaviour. What is the reason to implement it like this? What problems does you implementation solve or prevent? From what I can see, it's just limiting a very common use-case, without any reasonable benefits. If you really insist on this, at least make it optional with an input binding, so we can opt-out of it when we don't need it.

The only workaround for this is to use some other value, e.g. '' and then map it back and forth all over the place, for each mat-select. Honestly this is ridiculous. Totally messy, bug prone etc. and still a very poor workaround.

I haven't found a single workaround that would enable the desired behaviour in the use-case when you have your own component, implementing control value accessor, which wraps a mat-select.

Reproduction

http://plnkr.co/edit/i919jzNOoXhlPeN4hxxE?p=preview

Expected Behavior

Select should display text associated with null/undefined value when provided

Actual Behavior

Select displays nothing

Environment

  • Angular: 14,0,0
  • CDK/Material: 14.0.0
  • Browser(s): ALL
  • Operating System (e.g. Windows, macOS, Ubuntu): ALL

zolakt avatar Jun 20 '22 19:06 zolakt

@crisbeto Given this was a deliberate decision, is this considered working as intended? Or would you like to revisit this eventually?

wagnermaciel avatar Jun 24 '22 16:06 wagnermaciel

Yes, this is working as expected. The idea was to mimic the behavior of the native select and option elements with mat-select and mat-option.

crisbeto avatar Jun 25 '22 08:06 crisbeto

@wagnermaciel @crisbeto Sorry, but that is not an answer.

You haven't answered any of the questions that I've asked:

  1. What is the reason to implement it like this? It's simply not true that the native select behaves like this (see screenshot). It shows the text "NONE", not an empty string
  2. What problems does you implementation solve or prevent?
  3. Can you provide some workaround?
  4. Can you name just one lib (any framework, any technology) that works the way that your does?

image

I honestly don't get your reasoning. This is a needless limitation that is making a super common use case (optional filters, "ALL" options etc) nearly impossible to implement (at least without a totally dirty workaround, that needs to be repeated for every single mat-select)

You could at least make it optional. Instead of forcing a opinionated, weird, behaviour like this, for no good reason.

So no... this issues isn't "completed"... you are just refusing to address it... again, for no good reason.

Read the original thread... there are millions of use cases where this behaviour doesn't make any sense. So far I haven't seen a single one where it would be desirable. To me this looks like a case of a bruised ego. Instead of making it right, you refuse to acknowledge the fact that you made a poor design choice

zolakt avatar Jun 27 '22 13:06 zolakt

You still have the ability to control what the trigger looks like using the mat-select-trigger element. There's a live example in the docs: https://material.angular.io/components/select/examples#select-custom-trigger

crisbeto avatar Jun 27 '22 18:06 crisbeto

@crisbeto No you don't. I tried that already.

Here is a stackblitz example: https://stackblitz.com/edit/angular-l21cgb?file=src/app/select-custom-trigger-example.ts

The custom trigger is not shown either if mat-option value is "empty". In that case it shows the placeholder. And you can't use the placeholder for this purpose if you use floating labels. Even if you could, it would be an awful hack.

These lines are the problem: https://github.com/angular/components/blob/8ca012fdf63a540c0364d6acecd1d378f60f444e/src/material/select/select.html#L16-L22

Others have reported this already in the original thread. https://github.com/angular/components/issues/6466#issuecomment-332743725

There doesn't seem to be a clean workaround for this, not even close. Your argument that it mimics the native select is also not true. So again, what is the point in persisting with this weird behaviour that goes against every other select implementation? It's just limiting a whole bunch of extremely common use cases. This can't possibly take more than a few lines of code to make it work "normally", or at least to make this optional (since you are persisting with this so strongly).

zolakt avatar Jun 27 '22 18:06 zolakt

Alright, I'll reopen the issue but it's worth noting that there are other use cases that need to be considered. E.g. if we were to match the reset option to its label, the user won't have a way to put the select back into its initial state after selecting something.

crisbeto avatar Jun 27 '22 19:06 crisbeto

Thanks.

As others have suggested in the original thread. If the list of mat-options contains an "empty" value, than that initial/blank state doesn't make sense to begin with. So they shouldn't be able to get to it from the start, or after selection. That is how a native select works. There is no blank state.

And please don't treat null and undefined as the same thing. It's not. You could potentially treat undefined as a reset option, but null is definitely not some magical reset option. It is an explicit value.

This isn't ideal either, since that would still require us to define union types all over the place (e.g. value: string | null). It would be much cleaner if undefined was treated as a normal value, so we could simply define it as e.g. value?: string

In my opinion, the cleanest solution is to make this behaviour optional with a boolean input binding. Let the users choose the behaviour they want. Everything else is opinionated and limiting, in one direction or another.

zolakt avatar Jun 27 '22 20:06 zolakt

If the list of mat-options contains an "empty" value, than that initial/blank state doesn't make sense to begin with. So they shouldn't be able to get to it from the start, or after selection. That is how a native select works. There is no blank state.

Users may find that weird though since the form field around the select changes if a value is shown. For example you could have an empty form with a few input elements and a mat-select. The label of the inputs won't be floating, but the select will, despite the fact that you haven't interacted with it.

crisbeto avatar Jun 28 '22 07:06 crisbeto

And please don't treat null and undefined as the same thing. It's not. You could potentially treat undefined as a reset option, but null is definitely not some magical reset option. It is an explicit value.

FormControls change undefined values to null.

Totati avatar Jun 28 '22 09:06 Totati

Users may find that weird though since the form field around the select changes if a value is shown. For example you could have an empty form with a few input elements and a mat-select. The label of the inputs won't be floating, but the select will, despite the fact that you haven't interacted with it.

True. But the current behaviour is even more weird. You select something (with an "empty" value) and it just disappears. This is a functionality issue, compared to the opposite which is a UX issue, at best.

Although I don't think this decision should be affected by your touched state argument. The floating label doesn't represent if something has been touched or not. It represents if the value is empty or not. e.g. take a normal mat-input and type something. The label floats. Then delete your input. The label doesn't float anymore, even though you interacted with the component. The floating label doesn't represent if something was interacted with or not, it represents the empty state. Therefore if you are using an explicit "empty" mat-option, there is no empty/blank state, and the label should always float.

Making this optional is the cleanest way to go. Let the devs decide what is less weird for their use case.

FormControls change undefined values to null.

Yeah, true, I think this is weird as well. It converts undefined to null for the initial value, but not when you change selection. Pretty weird and inconsistent.

https://user-images.githubusercontent.com/1048531/176408691-9aef702d-114a-4ba1-8ed5-adfa75481fec.mp4

zolakt avatar Jun 29 '22 09:06 zolakt

Hey @zolakt, I wanted to thank you for the engagement in this issue and all the helpful information.

Going up the thread:

To me this looks like a case of a bruised ego. Instead of making it right, you refuse to acknowledge the fact that you made a poor design choice

I want to ensure that we're all focused on improving Angular, and I'd recommend assuming good intentions.

Such statements and personal attacks are not welcome in our communication channels. Let's stick to a constructive tone and collaborative environment.

mgechev avatar Jul 06 '22 23:07 mgechev

@mgechev I apologise for the harshness, it was impulsively written. There was no bad intention.

In my defence, it can be frustrating to try to get you guys into an argumented discussion. You have a tendency to close threads quickly, without really considering them thoroughly. This happened to the original thread. And then you did the same to this one immediately.

So again, I'm sorry if I offended anyone. I just hope this finally gets reconsidered and fixed. It's a 5 year old issue, that is pretty annoying.

zolakt avatar Jul 07 '22 08:07 zolakt

Any movement on this? it would be really nice to have mat select respect null value display text.

martine-dowden avatar Nov 09 '22 22:11 martine-dowden

Any news here ? In my case I have to bind a Boolean value to the mat-select, and so cannot represent/catch the null one :/

Lempkin avatar Jan 26 '23 16:01 Lempkin

5 years and we still don't have a solution or a workaround. Very frustrating.

enrique-lozano avatar Feb 06 '23 15:02 enrique-lozano

@mgechev @zolakt Please, we need this. Mapping to null is a very common case with dropdowns that display an "All" option. The only way right now is to map it to an empty string which makes less sense. As @zolakt said, please don't be so opinionated with this, let us devs choose what we want as value.

GabrielBB avatar Feb 14 '23 11:02 GabrielBB

While I do think the tone of this issue is far too harsh (bad decisions happen, and it's not always easy to undo the consequences), I also want to advocate for the ability to map to null. It would be great if this was revisited with flexibility in mind.

carlos-ds avatar Feb 23 '23 09:02 carlos-ds

@GabrielBB Why are you asking me :) I'm in the same boat as everyone else here, waiting for someone to finally fix this after 5+ years. The only workaround I have is to use 0 instead, which is incredibly stupid and tedious to maintain, but I found no better workaround

zolakt avatar Feb 28 '23 19:02 zolakt

My vote here as well, why do we need to think every time about what value to use for the "All" option, why to choose from nonlogical values ('', '-', '-1', '0' etc.) while "null" would be ideal...

prinf avatar Mar 14 '23 14:03 prinf

I agree that mapping to null is needed. Here is the workaround I've been using:

<mat-form-field floatLabel="always">
  <mat-label>State</mat-label>
  <mat-select placeholder="Any" formControlName="state">
    <mat-option [value]="null">Any</mat-option>
    <mat-option *ngFor="let state of states" [value]="state.id">
      {{ state.name }}
    </mat-option>
  </mat-select>
</mat-form-field>

msedge_tHTZNix0Lw

The downsides to this workaround:

  1. More code
  2. The default "Any" is grayed out, but after selecting "Any" from the list, it is no longer grayed out.

JWess avatar Apr 07 '23 19:04 JWess

https://github.com/angular/components/issues/25120#issuecomment-1500577134

This gif is basically the crux of the entire issue. My client just told me he wanted to see 'All' as the displayed value for empty field in one of the dropdowns inside his form.

That grey-out by default behavior is awkward for sure.

EDIT: I think (Jwess' idea of making the text for the empty-valued mat-option to be the same as the placeholder) + (styling the placeholder to not be greyed-out) is the only way to work around this for now

DibyodyutiMondal avatar Aug 10 '23 23:08 DibyodyutiMondal

Just wanted to chime in, the suggested workaround with mat-select-trigger does not work. In the example stackblitz I tried

    <mat-select-trigger>
      {{ foodCtrl.value ? foodCtrl.value : 'I am null'  }}
    </mat-select-trigger>

And it still displays the placeholder text, even though the value is null.

This stackblitz exhibits the problem with and without the mat-select-trigger, alongside a native select that works as intended: https://stackblitz.com/edit/4mzrpg?file=src%2Fexample%2Fselect-overview-example.html

inorganik avatar Nov 29 '23 16:11 inorganik

Best workaround I have found is to set the placeholder text to whatever you want to display for null and set floatLabel="always" on the mat-form-field

inorganik avatar Nov 29 '23 16:11 inorganik

I need that allows me to "clear" (with 'X' button on the control) and set default key/value where value is some string like "Make your selection" or "-- None --" which will be persisted as the absence of a selection ("null") in my model.

My attempt that uses default option item and ngStyle to hide: https://stackblitz.com/edit/4mzrpg-8rgyyg

abcox avatar Nov 30 '23 23:11 abcox

Any updates?

clarkmcc avatar Feb 13 '24 18:02 clarkmcc

Please, make this change, guys.

skyRoma avatar Apr 03 '24 15:04 skyRoma

Just wanted to chime in, the suggested workaround with mat-select-trigger does not work. In the example stackblitz I tried

    <mat-select-trigger>
      {{ foodCtrl.value ? foodCtrl.value : 'I am null'  }}
    </mat-select-trigger>

And it still displays the placeholder text, even though the value is null.

This stackblitz exhibits the problem with and without the mat-select-trigger, alongside a native select that works as intended: https://stackblitz.com/edit/4mzrpg?file=src%2Fexample%2Fselect-overview-example.html

Not sure where you have seen a workaround suggestion with mat-select-trigger. I've tested that already, commented that it doesn't work and posted the problematic code: here.

Although, I highly doubt anyone will ever fix that code, even after pointing out the exact problematic line. Personally, I've given up on waiting for this. The stupid workaround will have to do. If you wait for these guys to fix anything, you will never finish a single project. Now I'll probably get downvoted for pointing out the obvious, but sadly, that is reality... The issue has been reported 7 years ago...

zolakt avatar Apr 03 '24 20:04 zolakt