Components: Add guidance for styling invalid inputs

Created on 25 Apr 2016  路  25Comments  路  Source: angular/components

Note: for support questions, please use one of these channels:
https://github.com/angular/material2/blob/master/CONTRIBUTING.md#question.
This repository's issues are reserved for feature requests and bug reports.

  • Do you want to request a _feature_ or report a _bug_?
    Feature
  • What is the current behavior?
    The only class available on md-input is .md-focused
  • If the current behavior is a bug,
    please provide steps to reproduce and if possible a minimal demo of the problem

    via https://plnkr.co or similar.
  • What is the expected behavior?
    It would be great if the classes of ngControl could be transfered to the md-input label and the md-input underline, in order to display live return on the validity of inputs
  • What is the motivation / use case for changing the behavior?

Better User experience

  • Which version of Angular and Material, and which browser and OS does this issue affect?
    Did this work in previous versions of Angular / Material?
    Please also test with the latest stable and snapshot versions.
  • Other information
    (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix)
docs feature

Most helpful comment

For the time being, I'm using a md-hint to show my error messages:

<md-input>
    <md-hint *ngIf="error" [ngStyle]="{'color': 'red'}" align="start">{{errorMessage}}</md-hint>
</md-input>

It might help someone

All 25 comments

import {Directive, HostBinding} from '@angular/core';

@Directive({
    selector: '[input-error]'
})
export class InputErrorDirective {

    @HostBinding('attr.dividerColor')
    get isValid() {
         // Checks..
         return 'warn';
    }
}

The @HostBinding or better the setAttribute() function is not case-sensitive. This results in

<md-input [...] dividercolor="warn"></md-input> 

and unfortunately this don't work.

Any ideas?

For the time being, I'm using a md-hint to show my error messages:

<md-input>
    <md-hint *ngIf="error" [ngStyle]="{'color': 'red'}" align="start">{{errorMessage}}</md-hint>
</md-input>

It might help someone

Is there a class we can use linked to theming?

@krigton You can use the SASS md-color for theming,

.unicorn-carousel {
    color: md-color($warn);
}

see more on the guide

so no class already there for errors? we can put what we want?

Hi @krigton, yep. My solution is temporary.

Hope works for you.

You can use any color from material or create your own.

update from md to mat

Example:

@import '~@angular/material/core/theming/all-theme';
@include mat-core();

.red {
    color: mat-color($mat-red, 500, 1);
}

.warn {
   color: mat-color($warn);
}

@leocaseiro thanks

@leocaseiro Thanks for your idea.
But could you please explain, how to make two validation message?
For example, I have such a form:

<form [formGroup]="signUpForm" class="sign-up" (ngSubmit)="signUp(signUpForm)" >
      <md-input formControlName="fullName" placeholder="Full name">
        <md-hint *ngIf="signUpForm.hasError('required','fullName')" [ngStyle]="{'color': 'red'}" align="start">Full name is required</md-hint>
      </md-input>
      <md-input formControlName="userName" placeholder="User name">
        <md-hint *ngIf="signUpForm.hasError('required','userName')" [ngStyle]="{'color': 'red'}" align="start">User name is required</md-hint>
      </md-input>
      <md-input formControlName="email" type="email" placeholder="Email">
        <md-hint *ngIf="signUpForm.hasError('required','email')" [ngStyle]="{'color': 'red'}" align="start">Email is required</md-hint>
        <md-hint *ngIf="signUpForm.hasError('pattern','email')" [ngStyle]="{'color': 'red'}" align="start">[email protected]</md-hint>
      </md-input>
</form>

Hi @artem-galas,

I actually made my message error dynamic, so I have a single <md-hint>.

In that case, I update the message depending on the error.

If it's not clear, I'm happy to send you an example.

@leocaseiro Thanks, I got the idea. It would be awesome if you send me a snippet.

export class AppComponent {

  model = { email: '' }

  validateEmail(email) {
    var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
  }

  errorMessageEmail() {
    if (this.model.email === '') {
      return 'Email is required!';
    } else if (!this.validateEmail(this.model.email)) {
      return 'Email is invalid!';
    } else {
      return false;
    }
  }
}
  <form>
    <md-input placeholder="Email" [(ngModel)]="model.email" name="email" type="email" required>
      <md-hint *ngIf="errorMessageEmail()" [ngStyle]="{'color': 'red'}" align="start">{{errorMessageEmail()}}</md-hint>  
    </md-input>
  </form>

Here is the plunker: http://plnkr.co/edit/ZKd1OR2rpey3WddbEpRv?p=preview

PS: It's just a snippet for demo purpose, use ReactiveFormsModule for validation.

md-hint works fine for inputs, but there's no similar facility for select items, checkboxes, etc.

I created directives similar to ng1's ng-messages. Here's an example how you'd use it:

<md-input-container>
  <input mdInput formControlName="name" placeholder="Account name" required type="text">
  <md-hint [val-messages]="myForm.get('name')">
    <span val-message="required">Required</span>
  </md-hint>
</md-input-container>

The example above conviniently slaps it on md-hint, but you can put it on any html element.
I know this does not directly addresses the issue, but hopefully helps a bit.

How to divider color for md-select? I have got validations to work on inputs on submit but for select it works only if you have touched it once atleast and then click submit.

@abqadeer, can you give an example of how you got the validations on submit to work?
I could not figure out how to set touched on elements on submit for it to work correctly.

however i did the following for the error message colors:
+input did not mark errors in red
+select does not have a container, so not md-hint. So i created one that mocked it.

md-input-container.ng-touched.ng-invalid {
    /deep/ .mat-input-placeholder {
        color: $error;
    }

    /deep/ .mat-input-underline {
        border-top-width: 1px;
        border-color: $error;
    }

    /deep/ .mat-input-ripple {
        background-color: $error;
    }

    md-hint {
        color: $error;
        float: right;
    }
}

div.select-container {
    position: relative;

    .md-hint {
        color: $error;
        padding-top: 2px;
        font-size: 75%;
        position: absolute;

        right: 0;
    }
}

I just realized they they added md-error ... and the need for some of my css is no longer needed. However I still dont know how to make the input trigger in error when you have not touched it.

@tmburnell , there is a workaround described in #4232 for allowing the md-error to show an error even if the control is not touched.

@tmburnell running .valid on the input form will also show the md-error on all invalid inputs. (*for reactive forms)

If this can help someone, md-error works fine with formControl, for example:

[HTML]

          <fieldset [disabled]="isSubmitting">
                <md-input-container class="full-width">
                    <md-error>{{tagField.errors ? tagField.errors.missedTag : null}}</md-error>
                    <input mdInput class="article-tags" type="text" placeholder="Enter tags"
                           [formControl]="tagField" (keyup.enter)="addTag()"/>
                    <md-chip-list>
                        <md-chip *ngFor="let tag of article.tags">
                            <md-icon (click)="removeTag(tag)">delete</md-icon>
                            <span>{{tag}}</span>
                        </md-chip>
                    </md-chip-list>
                    <md-hint>Press [enter] to add the tag</md-hint>
                </md-input-container>
            </fieldset>
            <fieldset [disabled]="isSubmitting">
                <button md-raised-button type="button" (click)="submitForm()" [disabled]="checkValidForm()">
                    <md-icon>publish</md-icon>
                    <span>Submit</span>
                </button>
            </fieldset>

[TS]

this.fb.group({tagField: []});

checkValidForm(): boolean {
        if (this.article.tags.length < 1) {
            this.tagField.setErrors({'missedTag': 'Please add at last one tag'});
        }
        return !this.articleForm.valid || this.article.tags.length < 1;
}

Closing this since we now have <md-error> and a section in the input documentation on how to use it

@mmalerba - we do? The documentation on https://material.angular.io/components/input/overview is broken, I can't see example code and Plunkers don't do anything, and docs don't even try to explain how to have multiple messages.

The docs seems to be broken here as well. Was looking forward to experimenting with this feature, but will have to wait a while until everything is back to normal.

@davorzdralo Confirmed still broken on my end.

@davorzdralo @steve-todorov @atbe

Dunno why that particular example is broken (cc @amcdnl), but the source is here:

https://github.com/angular/material2/tree/master/src/material-examples/input-errors

and here's the example in a plunker:

https://plnkr.co/edit/mS8vyDKHLUhC9YOr84Aw?p=preview

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings