angular / components

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

Provide Automatic Binding of FormControl Error Messages and Status to input hints #2810

Open arciisine opened 7 years ago

arciisine commented 7 years ago

Bug, feature request, or proposal:

This is a feature request.

This is related to #348, but is specifically asking for the material guidance to be a part of the framework, integrating with standard functionality of @angular/forms.

What is the expected behavior?

Looking at Material Error Patterns, there seems to be a standard behavior of inlining form error message into the hint area (with a specific color).

screen shot 2017-01-25 at 6 58 03 pm

It also supports separating the existing hint from the error message via a comma.

screen shot 2017-01-25 at 6 59 02 pm

What is the current behavior?

Error state and messages are not handled.

What are the steps to reproduce?

There is nothing to show as this is feature that is yet to be implemented. Material Error Patterns should provide the expected behavior and visual treatment.

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

The general gist is that if everyone were to follow the guidelines from material.io, you would end up with a fair amount of duplicate code for every input. The pervasiveness of the desired functionality seems like a prime candidate for handling at the framework level.

Which versions of Angular, Material, OS, browsers are affected?

All

Is there anything else we should know?

arciisine commented 7 years ago

I would be interested in opening a PR to support this, if the material team thinks this is a valid feature.

arciisine commented 7 years ago

For anyone else looking at this, we have a very simple (not robust) implementation that should help along these lines. Currently its only setup for <md-input-container> but should be pretty easy to extrapolate.


import {
  Directive, ViewContainerRef, OnInit,
  HostListener, ContentChild, AfterViewInit, ContentChildren
} from '@angular/core';
import { NgControl, FormControl } from '@angular/forms';
import { MdInputDirective, MdInputContainer } from '@angular/material';

@Directive({
  selector: 'md-input-container'
})
export class ValidationDirective implements AfterViewInit {

  @ContentChild(MdInputDirective) mdInput;

  constructor(private container: MdInputContainer) { }

  ngAfterViewInit() {
    let ctrl = this.mdInput._ngControl as NgControl;
    if (ctrl === null) {
      // handles when field is not attached to form
      return;
    }
    let ogHint = this.container.hintLabel;
    let formCtrl = ctrl.control;
    // Not an easy way to see what validators are actually on a control, and so we assume if an
    //   empty input produced an error, the field is required
    if (formCtrl && formCtrl.validator) { 
      let res = formCtrl.validator(new FormControl());
      if (Object.keys(res).length > 0) {
        this.mdInput.required = true;
      }
    }
    ctrl.statusChanges.subscribe(() => {
      let messages = [ogHint];

      if (ctrl.invalid) {
        messages.push(...Object.keys(ctrl.errors)
          .map(x => ctrl.errors[x])
          .map(m => m.includes('required') ?
            'This field is required' :
            m));
      }

      let message = messages.filter(x => !!x).join(', ');
      this.container.hintLabel = message;
    });
  }
}
arciisine commented 7 years ago

@kara @mmalerba I see there is a PR #3114 that address part of this issue. Is that to indicate that this ticket will also make it in at some future point, or is that still in the discussion phase?

mmalerba commented 7 years ago

We still need to discuss the error messages part of it.

iliketomatoes commented 7 years ago

If we could have something like this: https://material.angularjs.org/latest/demo/input, it would be awesome. Thanks!

natsid commented 7 years ago

As the error message feature gets expanded to include other form controls (checkboxes, radio buttons, ...), would it be possible to implement a "group-level" error message, i.e., a message that applies to a group of associated form controls?

Select 'green' in this plunkr to see an example: http://plnkr.co/edit/HhN7ykzp0oM07IGyy4a3?p=preview

jefersonestevo commented 7 years ago

I've developed a component to get and show the error messages from another component. It's pretty straighforward to use, you only need to provide the control (NgModel or FormControl) from the component to it and it will handle the messages. You can even customize the message you want to show for each erro by providing templates with a custom directive.

There are some pros and cons to this approach.

Pros:

Cons:

You can see the demo here: https://rawgit.com/jefersonestevo/angular-smd/master/dist/index.html#/angular-smd/demo-error-messages

Hopefully this component may help you with some ideas. I'm using it for now.

mmalerba commented 7 years ago

fyi error messages part is in progress: #3560

mmalerba commented 7 years ago

Closing since this has been implemented via <md-error>

arciisine commented 7 years ago

@mmalerba I don't believe <md-error> provides any form of automatic binding of FormControl error messages. As I understand it, it is only used for specifying error messages one by one, but nothing automatic, which is the goal of this issue.

mmalerba commented 7 years ago

Ah sorry, will re-open this for discussion

ZachRoberts25 commented 6 years ago

it would be great to be able to dynamically add error messages as they come from HTTP requests, which is what I am thinking @arciisine is referring to.

To be able to set errors directly on the FormControl dynamically would allow for a lot less duplicated code.

BenRacicot commented 5 years ago

I submitted a feature request which Kara linked to 21823 that I think may be very similar but related to form success messages. Basically the idea comes down to being able to CRUD statusChanges.

I hope it's ok to reference that here.