angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.37k stars 6.75k forks source link

FR: Create a component that adds validation and error messages to any form control #7891

Open aitboudad opened 7 years ago

aitboudad commented 7 years ago

Bug, feature request, or proposal:

feature request

What is the current behavior?

can't use checkbox and radio inside form-field.

What is the use-case or motivation for changing an existing behavior?

form-field provide a common way to display field description (hints) and message errors and I would like to have the same behavior for checkbox and radio.

halukkaramete commented 7 years ago
<mat-form-field class="example-medium-width">
        <mat-select matInput name="cars" [(ngModel)]="vehicles.cars" placeholder="Cars" multiple #field_cars="ngModel">
            <mat-option *ngFor="let car of cars" [value]="car">
                {{ car }}
            </mat-option>
        </mat-select>

    </mat-form-field>

The Select implementation here is pretty standard for template-driven forms and it works like a charm. Thanks to the "multiple" here, one can select multiple values and then cars are submitted nicely which are all part of one single variable. Easy to cycle thru, easy to paint. No maps to deal with, No code to manage indexes, none of that. You get your cars as an array! Just cannot get any better than that.

I hope that when the checkbox implementation is done, it would be done the same way so it will be as easy and as consolidated as the select implementation in my example. I should be able to group checkboxes under one group and handle that hassles free just like the current select box

leocaseiro commented 7 years ago

How about add mat-slider to the list?

leocaseiro commented 7 years ago

Very Ugly temporary hack that hurts

Wrap a mat-form-filed with always floatPlaceholder and add a matInput that it's display:none.

<mat-form-field floatPlaceholder="always" class="mat-form-field--no-underline">
  <!-- the matInput with display:none makes the magic. It's ugly, I've warned you -->
  <input matInput placeholder="Input" style="display: none" >
  <mat-radio-group>
    <mat-radio-button value="1">Option 1</mat-radio-button>
    <mat-radio-button value="2">Option 2</mat-radio-button>
  </mat-radio-group>
</mat-form-field>

Now, we just need a workaround to remove the mat-input-underline.

.mat-form-field--no-underline .mat-input-underline {
  background-color: transparent;
}

Result

screen shot 2017-11-08 at 1 33 06 pm

PS: Make sure you share your formControlName between mat-radio-group/mat-checkbox and the ugly [matInput] {display:none}

Eq: http://plnkr.co/edit/NrihcY?p=preview

leocaseiro commented 6 years ago

I was learning about the mat-selection-list and I've realized that it comes with a Label as [mat-subheader].

It turned out it works for checkboxes and radio group as well.

Try something like so:

RadioGroup

<mat-list>
    <h3 mat-subheader>Label for RadioGroup</h3>
    <mat-radio-group class="example-radio-group" [(ngModel)]="favoriteSeason">
    <mat-radio-button class="example-radio-button" *ngFor="let season of seasons" [value]="season">
      {{season}}
    </mat-radio-button>
  </mat-radio-group>
</mat-list>

Checkbox Group

<mat-selection-list #groceries>
  <h3 mat-subheader>Groceries</h3>

  <mat-list-option checkboxPosition="before" value="bananas">Bananas</mat-list-option>
  <mat-list-option checkboxPosition="before" selected value="oranges">Oranges</mat-list-option>
  <mat-list-option checkboxPosition="before" value="apples">Apples</mat-list-option>
  <mat-list-option checkboxPosition="before" value="strawberries">Strawberries</mat-list-option>
</mat-selection-list>

Eq: https://plnkr.co/edit/k73FSy?p=preview

mmalerba commented 6 years ago

@tinayuangao I don't think we want to have radio buttons or checkboxes inside of form fields. form fields are only intended for things that have the floating label & underline style that input and select share. But error messages on radio & checkboxes is a reasonable request

leocaseiro commented 6 years ago

Perhaps what is missing is a label that could be used as a field description for fields, such as radio-group, checkbox list, slider and some others

leocaseiro commented 6 years ago

I guess we can always use Material Typography such as .mat-h4 or just wrap the <h4> in a .mat-typography:

<section class="mat-typography">
  <h4>Label for RadioGroup</h4>
  <mat-radio-group class="example-radio-group" [(ngModel)]="favoriteSeason">
    <mat-radio-button class="example-radio-button" *ngFor="let season of seasons" [value]="season">
      {{season}}
    </mat-radio-button>
  </mat-radio-group>
</section>
oktav777 commented 6 years ago

Also mat-selection-list should be wrapable in mat-form-field too, for a common style of validation messages, hints, etc.

anthony-o commented 6 years ago

I've just created a new issue (https://github.com/angular/material2/issues/11333) presenting the expected behavior in another way: I just asked to support validation errors on such inputs.

ruant commented 6 years ago

Just wondering how this hasn't been implemented.
This must be a must for a lot of people. (Pun intended)

Chris2011 commented 6 years ago

I have the same problem. For me I need the error message, when it is required and nothing was checked, inside a mat-readio-group. And the required indicator * is missing. It is set dynamically. Sure, I can add it again with ngIf and a new tag but it radio buttons and checkboxes are form fields, since the beginning. Input, textarea, checkbox, radio buttons and smth more.

hsinyu-chen commented 6 years ago

all controls should work inside form-field. now I have to do extra work to make all the fields look consistently (label hint ...) and I need to remember if use mat-raido-group or checkbox then I need use my-form-field instead of mat-form-field that is very annoying

AshurovRustam commented 6 years ago

Still no solution with this problem? Tried today to put checkbox of form (reactive approach) and had to add custom styles to make it fit vertically right because impossible to put checkbox inside mat-form-field. Also mat-error is dispayed not correctly (probably cuz it is not inside mat-form-field afterall).

aitboudad commented 6 years ago

wrapping them in form-field would do the job, that's what I did for ngx-formly integration: https://formly.dev/ui/material

LayZeeDK commented 6 years ago

wrapping them in form-field would do the job, that's what I did for ngx-formly integration: https://formly-js.github.io/ngx-formly/ui/material

Sure, but you provide your component as MatFormFieldControl and implement MatFormFieldControl<T>.

import { MatFormField, MatFormFieldControl } from '@angular/material';

@Component({
  // (...)
  providers: [{ provide: MatFormFieldControl, useExisting: FormlyWrapperFormField }],
})
export class FormlyWrapperFormField implements MatFormFieldControl<any> {
  // (...)
}

Since Angular Material version 7 there is a guide for doing this with custom controls: Creating a custom form field control

We should be able to add this feature in the same way for the Angular Material radio buttons and checkboxes.

We should also look into how the Angular Material select component implements this.

JonesM87 commented 5 years ago

Any update on a fix for this? This has been a recurring issue for many for quite a long time now...

danielnitu commented 5 years ago

I was having troubles hiding the underline. Eventually worked using ::ng-deep

::ng-deep .mat-form-field--no-underline .mat-form-field-underline { background-color: transparent !important; }

biltongza commented 5 years ago

I'd like to add button toggle groups to this request, they basically behave the same as radio groups with different styling.

ksuhiyp commented 5 years ago

Can we know what is the point behind not supporting checkbox and radio in mat-form-field?

MihailProcudin commented 5 years ago

Having issue tho with Radio Buttons. Set them up as required and after user submit the form without checking the radio buttons, he doesn't get any error message. Very weird thing ...

james-schwartzkopf commented 5 years ago

Here is the solution we are using: https://stackblitz.com/edit/material-if-errors?file=app%2Fif-error.ts

It has the advantage that it can be used to show errors for any control. Since most error matchers just check touched, dirty, and valid, you could get away with passing it a FormGroup cast to a FormControl to show errors at the group level.

jcanning commented 5 years ago

Still looking for an update to this. Any progress?

franklinpious commented 5 years ago

Came searching for an update on this multiple times.

jelbourn commented 5 years ago

(I'm going through the highest voted issues today an commenting on their status)

We currently don't have any active plans to work on this, primarily because we don't really see how it fits in with the Material Design spec. What we call "form-field" maps to text fields. We used the term "form-field" since the spec clearly shows the treatment being used for selects/dropdowns as well. The spec doesn't, though, show any other type of interaction with this treatment; our interpretation here has been that directly supporting it wouldn't be in the spirit of the Material Design spec.

That said, there is an API for using any control inside of MatFormField. You can create a custom directive like myCustomFormControl that extends MatFormFieldControl to integrate with the form-field (example in the docs) and then apply this custom directive to any component you need.

garg10may commented 5 years ago

:( bootstrap supports checkboxes and radio buttons inside forms, they are so common everywhere. What would I do when my client asks please add the checkboxes, radio buttons for Yes/No, I have seen them elsewhere. I would be like u know what we are elite we are material.

P.S. - hope he doesn't know about custom directives :P

hsinyu-chen commented 5 years ago

OK , so we need open an issue at Material Design spec's github then.

maccurt commented 5 years ago

As a developer, I DO NOT like the attitude of you don't need what you want to do, but then I am not paying for this so I just suck it up and move one. But yes it would be very nice to add the check box inside the form fields, because, well check boxes are on forms.

royyhlee commented 5 years ago

I'd like to have some sort of checkbox-group that can be put inside mat-form-field. For example, we want to create a field where we want the user to check all the categories that they have interest in. I don't want to use selection list because if I have a lot of options, it takes up a lot of space. I think it is very reasonable to have radio-group & checkbox-group inside a form field so it can have label, hint, & error validation.

CharlieReitzel commented 4 years ago

@jelbourn Hi Jeremy, here is the Material design description of checkboxes:

https://material.io/components/selection-controls/#checkboxes

How do you interpret the spec to exclude non-textual form controls? The other Material "selection controls" are radio buttons and switches. Other non-textual controls described include sliders and various buttons.

Further, in the description of "Form Fields", the very 1st example is a check box!?! https://material.io/develop/web/components/input-controls/form-fields/

Can you share a link to where in the spec it says, "What we call 'form-field' maps to text fields"?

My instinct is that you are, perhaps, interpreting the spec too literally in this case. I.e. you are taking anything not expressly permitted as denied. In this case, anything not expressly denied, that fits into common use and aligns with other existing web standards, should be encouraged.

mmalerba commented 4 years ago

@CharlieReitzel what @jelbourn is saying is that the thing we (Angular Material) call <mat-form-field> corresponds to what the Material Design spec calls a "Text field" https://material.io/components/text-fields/ (yes, the differing terminology is confusing). We currently don't have any single component that corresponds to a generic form control wrapper, we have <mat-checkbox> for checkboxes, <mat-radio> for radio buttons, and <mat-form-field> for text inputs and selects.

CharlieReitzel commented 4 years ago

@mmalerba @jelbourn I understand what Jeremy said. I am asking for more information about the rationale behind that decision. Specifically, I am asking, where in the Material Design and Angular Component specifications that limitation is stated? Can you please share the relevant spec(s)?

Again, my feeling is that it isn't being read quite right. That association seems altogether too narrow to be truly useful to developers. I have worked around it for the moment. But the results are not satisfactory. As others have said, most <mat-form-field> features are not specific to text fields, e.g. displaying validation errors, highlighting controls with errors, label display, etc.

mmalerba commented 4 years ago

There is nowhere in the spec, as far as I know, that discusses validation and error messages for checkboxes, radio buttons, etc. I think some kind of generic form control container is a reasonable thing to ask for, though without any mention of it in the spec, it's not going to be a high priority for the team.

mmalerba commented 4 years ago

I've renamed this issue to avoid any confusion about mat-form-field, what this issue is asking for would be implemented as a separate new component

CharlieReitzel commented 4 years ago

@jelbourn said,

We currently don't have any active plans to work on this, primarily because we don't really see how it fits in with the Material Design spec.

All I'm asking is which spec (link please)? And where in it are you seeing that you shouldn't support both text fields and selection controls under <mat-form-field>? There is clearly a lot of support in favor of this feature request. So, at a minimum, it will help us all understand your reasoning.

I'm seeing this, in Introduction to Material Design, Components:

Material Components are interactive building blocks for creating a user interface, and include a built-in states system to communicate focus, selection, activation, error, hover, press, drag, and disabled states.

A bit later, as part of a list of components,

Input: Entering information or selections, using components such as text fields, chips, and selection controls.

"Selection controls" refer to check box, radio button and switch components, collectively. So I'm seeing fairly direct support in (what looks like) the Material Design "spec" for what the OP and many others are asking. So, please, can you tell us? What are we all missing?

mmalerba commented 4 years ago

<mat-form-field> is a detail of our implementation of the spec, so the spec says nothing about it. It is completely separate from the concept of "selection controls" in the spec. I really don't know how to explain this any better, I feel like I'm just repeating myself.

Separately, the idea of validation and errors that applies universally to any form control sounds like a good idea to me, but it is not something that the spec covers. I can't link you to where it doesn't cover it because... it's not in the spec. Nowhere does it show what an error message for a checkbox would look like. I'd prefer to see the spec add some guidance on this rather than just making up our own UI and having it turn out to be completely off spec later on

CharlieReitzel commented 4 years ago

@mmalerba Are you talking about this spec: Angular Material Components? Or this one: Material Design "Design"? Or something else?

mmalerba commented 4 years ago

I'm referring to the second one; the first one is not a spec, it's the documentation site for this project

bgilbert6 commented 4 years ago

please add this, or rename mat-form-field to something else and make a new component to wrap all controls

JohnYoungers commented 4 years ago

I'm late to the party on this: I think it's apparent after 2.5 years there's no interest from the component group on hooking these inputs up to mat-form-field, but unfortunately for me our UX requirements aren't 100% on board with the material specification I guess.

Before I jump on the pain train tomorrow and create my own: has anyone already created a basic MatFormFieldControl directive that can be applied to the non-'text' fields (specifically MatSelectionList)?

Really all I need is for the styling (error handling) to function, and I'd rather not add hidden inputs everywhere.

james-schwartzkopf commented 4 years ago

Really all I need is for the styling (error handling) function, and I'd rather not add hidden inputs everywhere.

There are several workarounds upthread. If all you are worried about is showing errors, the ifError directive I posted should work. I notice our current implementation is different from that stackblitz, so I updated it.

https://stackblitz.com/edit/material-if-errors?file=app%2Fif-error.ts

salem017 commented 4 years ago

Any update on it. I use the alternative methods `

Utilisateur active
      </div>

` Form control Name work on this case

herman-rogers commented 3 years ago

Still a problem in 2021 - I think the general attitude is that "we know whats best for you" and so the workarounds continue.

We were able to make this work (for us at least) by adding in a custom label and relevant form errors below the checkbox.

<div class="flex-column p-b-large">
  <label for="exampleCheck">
    Checkbox example label:
    <span class="required" aria-hidden="true"></span>
  </label>

  <mat-checkbox id="exampleCheck" formControlName="checked">
    I Accept
  </mat-checkbox>

  <mat-error *ngIf="formErrors('checked')">
    You must accept to continue.
  </mat-error>
</div>
cwuerzlhuber commented 3 years ago

Also having same need, to add proper error messages to checkbox or radio groups.

@herman-rogers, your workaround is also just working partly. In that way the mat-error will not be correctly linked to the checkbox controls, so the error will not be correctly announced via screen readers for example. Normally the mat-form-field connects those and also adds all the necessary aria attributes, to make the error also accessible.

jcphlux commented 3 years ago

Here is my hacky contribution inspired by @leocaseiro. I needed validation. I did not need labels so see @leocaseiro example for that.

// This is all for a hacky fix to make radio buttons work with validation
.form-field-radio-group {
  &.mat-form-field-invalid .mat-radio-group{
    color: red;
    ::ng-deep .mat-radio-outer-circle{
      border-color: red;
    }
  }
  .mat-input-element {
    display: none
  }
  ::ng-deep .mat-form-field-underline {
      display: none
  }
}
<mat-form-field class="form-field-radio-group">
  <input matInput formControlName="stuff">
  <mat-radio-group formControlName="stuff">
    <mat-radio-button value="1">Option 1</mat-radio-button>
    <mat-radio-button value="2">Option 2</mat-radio-button>
  </mat-radio-group>
  <mat-error *ngIf="stuff.invalid">{{getErrorMessage()}}</mat-error>
</mat-form-field>
rozhanroukhosh commented 3 years ago

2021 and still the issue is around for the checkbox!!!

DanielHabenicht commented 2 years ago

I've implemented a Directive to emulate the MatFormAccessor for any NgControl, which you would use like this:

<mat-form-field>
  <mat-label>Application Active</mat-label>
  <mat-slide-toggle formControlName="active" workaroundMatFormAccessor>
    Active
  </mat-slide-toggle>
</mat-form-field>

Should work for other usecases but I didn't test it yet, maybe I will setup a small npm package for it.

Code: https://gist.github.com/DanielHabenicht/b98beadb1f8e099f942053076f835bcc

palmtreefrb commented 2 years ago

I've implemented a Directive to emulate the MatFormAccessor for any NgControl, which you would use like this:

<mat-form-field>
  <mat-label>Application Active</mat-label>
  <mat-slide-toggle formControlName="active" workaroundMatFormAccessor>
    Active
  </mat-slide-toggle>
</mat-form-field>

Should work for other usecases but I didn't test it yet, maybe I will setup a small npm package for it.

Code: https://gist.github.com/DanielHabenicht/b98beadb1f8e099f942053076f835bcc

@DanielHabenicht Thanks, this works for me with mat-checkbox.

      <mat-form-field class="demo-full-width">
        <mat-label>Active</mat-label>
        <mat-checkbox formControlName="active" workaroundMatFormAccessor>
        </mat-checkbox>
      </mat-form-field>
wshaver commented 2 years ago

I've implemented a Directive to emulate the MatFormAccessor for any NgControl, which you would use like this: Code: https://gist.github.com/DanielHabenicht/b98beadb1f8e099f942053076f835bcc

Thanks @DanielHabenicht that saved me a bunch of time!

If you're using an older version of Angular that doesn't implement hasValidator you can do this instead for the required() getter in WorkaroundMatFormAccessorDirective

get required(): boolean {
    const control = this.ngControl.control;
    if (!(control && control.validator)) {
      return false;
    }
    const validator = control.validator({} as AbstractControl);
    return validator && validator.required;
  }
frozenfrank commented 1 year ago

It's now 2023. Any comment on why this feature is no longer under consideration? @andrewseguin

andrewseguin commented 1 year ago

There are a couple reasons that we won't be able to commit to this work. The main reason is simply that supporting this is a lower priority than the current work of moving towards the latest Material Design spec. Second, there is no spec that we could use to implement errors for components other than input and select.

We would truly love to add this in (and many other highly requested features), but unfortunately we only have so many resources to work with.