angular ng-messages only showing when $touched is true
Asked Answered
F

4

14

I am not doing anything too special.

I have an input I want validated with every key stroke. If validation fails, display the error. Do not wait for the blur event to trigger the $touched.

I thought this was the default case, but apparently it is not. I am using angular materials along with angular messages. I am doing this for capslock detection.

The markup:

<form name="primaryLogin" novalidate>
    <md-content layout-padding layout="column">
        <md-input-container flex>
            <label>Login ID</label>
            <input type="text" required="" name="login" ng-model="primary.loginID" capslock>

            <div ng-messages="primaryLogin.$error">
                <div ng-message="required">
                    Please enter a Login ID.
                </div>

                <div ng-message="capslock">
                    Caps Lock is ON!
                </div>
            </div>

            <pre>{{ primaryLogin | json }}</pre>

        </md-input-container>

    </md-content>
</form>

When I first come to the page, turn caps lock on, and start typing, my error message looks like so:

{
  "$error": {
    "capslock": [
      {
        "$viewValue": "Q",
        "$validators": {},
        "$asyncValidators": {},
        "$parsers": [
          null
        ],
        "$formatters": [
          null,
          null
        ],
        "$viewChangeListeners": [],
        "$untouched": false,
        "$touched": true,
        "$pristine": false,
        "$dirty": true,
        "$valid": false,
        "$invalid": true,
        "$error": {
          "capslock": true
        },
        "$name": "login",
        "$options": {
          "debounce": 100,
          "updateOnDefault": true
        }
      }
    ]
  },
  "$name": "primaryLogin",
  "$dirty": true,
  "$pristine": false,
  "$valid": false,
  "$invalid": true,
  "$submitted": false,
  "login": {
    "$viewValue": "Q",
    "$validators": {},
    "$asyncValidators": {},
    "$parsers": [
      null
    ],
    "$formatters": [
      null,
      null
    ],
    "$viewChangeListeners": [],
    "$untouched": true,
    "$touched": false,
    "$pristine": false,
    "$dirty": true,
    "$valid": false,
    "$invalid": true,
    "$error": {
      "capslock": true
    },
    "$name": "login",
    "$options": {
      "debounce": 100,
      "updateOnDefault": true
    }
  }
}

So this seems to be working as expected, but the actually error message doesn't display until the blur event fires on that particular input.. So I can go in with capslock, type 10 characters, the error object says the capslock error is there, but since $touched isn't true, then it doesn't show.

Once $touched is set to true, then I can go back into the input and everything works like expected.

Any ideas? Thanks in advance!

Flosi answered 16/12, 2015 at 23:48 Comment(3)
What is the capslock attribute?Hallo
@Hallo The capslock attribute is a custom directive for capslock detection. It has its own error state to display messages.Flosi
Note : usually when you want to force people use lowercase, you just force the lowercase instead of validation see #16389062Viole
H
21

Change

<div ng-messages="primaryLogin.$error">

to

<div ng-messages="primaryLogin.$error" ng-show="primaryLogin.login.$dirty">

You may also try

<div ng-messages="primaryLogin.$error" ng-show="primaryLogin.login.$touched">

OR

<div ng-messages="primaryLogin.$error" ng-show="primaryLogin.login.$pristine">

You can also club them like so for conditional AND check:

<div ng-messages="primaryLogin.$error" ng-show="primaryLogin.login.$dirty && primaryLogin.login.$touched && primaryLogin.login.$pristine"> 

or for conditional OR check:

<div ng-messages="primaryLogin.$error" ng-show="primaryLogin.login.$dirty || primaryLogin.login.$touched || primaryLogin.login.$pristine">

Try the above one by one to find out whichever one meets your case.

Heartstrings answered 21/1, 2016 at 8:36 Comment(3)
Thank you sir. Adding ng-show="primaryLogin.login.$dirty" did the trick. I though that ng-messages handled it its own ng-show. Can you give some explenation on why that works?Flosi
@Flosi ng-messages starts showing error messages as soon as the page loads. But you may not want it. You may want to control when to show those error messages. $dirty means that user has interacted with the element. So for the input type text, that would mean that user has entered some text (even a single character is caught). This is NOT blur, so user can still have his cursor in the textbox and keep entering something and all that will be caught by $dirty. $touched is where user clicked on a control but moved away without releasing it. $pristine is where user did not click/blur a control.Heartstrings
#50464567Sapsago
A
4

In Pre 1.0 version of Angular Material (i.e. <= v0.11.4), that was the case: The ng-message was displayed by default.

However, the material design spec states:

Show error text only after user interaction with a field. If the user inputs incorrect data, helper text may transform into error text.

If you want to show messages before the user's interaction, you can add "md-auto-hide='false'" to your ng-messages directive.

<div ng-messages="primaryLogin.$error" md-auto-hide='false'></div>

I found this solution from: here

Amidase answered 25/1, 2016 at 23:38 Comment(1)
it would be great but it doesn't help. Check this one: codepen.io/anon/pen/RGRgoN . Even if you add md-auto-hide then messages for email are not displayed on page load.Mccollum
T
1

Check with ng-show="primaryLogin.login.$invalid && primaryLogin.login.$touched". This did the trick for me.

Tarrant answered 19/12, 2016 at 10:30 Comment(0)
C
1

Use md-is-error exampl:

<md-input-container md-is-error="true">

"When the given expression evaluates to true, the input container will go into error state. Defaults to erroring if the input has been touched and is invalid."

https://material.angularjs.org/1.1.3/api/directive/mdInputContainer

Cozy answered 6/4, 2017 at 13:23 Comment(1)
This is the best as ng-show or ng-if messes up with ng-messages animations. Instead of just true for md-is-error message if we put the condition in md-is-error it works as a charm. Thanks.Then

© 2022 - 2024 — McMap. All rights reserved.