AngularJS: Show form input error on change / typing / immediately

2.8k views Asked by At

If you delete the initial text that is in the input element in the example below, then it will not show an error until you blur the element.

I want to have the input element underline turn red and the error show immediately when you delete the last character in the input.

Any ideas somebody?

var app = angular.module('myApp', ['ngMaterial', 'ngMessages']);

app.controller('DemoCtrl', function() {
  this.name = 'test text';
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Angular JS</title>
  <link
    rel="stylesheet"
    href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.6/angular-material.min.css">
</head>
<body ng-app="myApp">
  <div ng-controller="DemoCtrl as demo">
    <form name="testForm">
      <md-input-container>
        <input
          name="testInput"
          ng-model="demo.name"
          required
          aria-label="test input"
          type="text">
        <ng-messages
          for="testForm.testInput.$error"
          role="alert">
          <ng-message when="required">
            <span>
              required
            </span>
          </ng-message>
        </ng-messages>
      </md-input-container>
    </form>
  </div>
  
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-animate.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-aria.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-messages.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.6/angular-material.min.js"></script>
</body>
</html>

2

There are 2 answers

4
Claies On BEST ANSWER

This is a quirk with the way the animations are triggered within an md-input-container. Angular Material has a flag that allows you to change when the input is checked for errors, to minimize the animation loop. The defaults are a bit too restrictive, but can be changed.

md-input-container has an optional flag that can be added: md-is-error. This allows you to pass an expression to control when the input is checked for errors.

try this: <md-input-container md-is-error="testForm.testInput.$invalid">

var app = angular.module('myApp', ['ngMaterial', 'ngMessages']);

app.controller('DemoCtrl', function() {
  this.name = 'test text';
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Angular JS</title>
  <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.6/angular-material.min.css">
</head>
<body ng-app="myApp">
  <div ng-controller="DemoCtrl as demo">
    <form name="testForm">
      <md-input-container md-is-error="testForm.testInput.$invalid">
        <input name="testInput"
               ng-model="demo.name"
               required
               aria-label="test input"
               type="text">
        <ng-messages for="testForm.testInput.$error" role="alert">
          <ng-message when="required">
            <span>
              required
            </span>
          </ng-message>
        </ng-messages>
      </md-input-container>
    </form>
  </div>
  
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-animate.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-aria.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-messages.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.6/angular-material.min.js"></script>
</body>
</html>

1
lin On

One way to achieve this is by adding ng-change="testForm.$setSubmitted()" to your inputs. This will directly trigger the form validation on change. While using testForm.$setSubmitted() on ng-change your need to check your dependend functions. Maybe some other behaviors inside your application could be effected.

<input name="testInput"
       ng-model="demo.name"
       ng-change="testForm.$setSubmitted()"
       required
       aria-label="test input"
       type="text">

Example:

var app = angular.module('myApp', ['ngMaterial', 'ngMessages']);

app.controller('DemoCtrl', function() {
  this.name = 'test text';
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Angular JS</title>
  <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.6/angular-material.min.css">
</head>
<body ng-app="myApp">
  <div ng-controller="DemoCtrl as demo">
    <form name="testForm">
      <md-input-container>
        <input name="testInput"
               ng-model="demo.name"
               required
               aria-label="test input"
               ng-change="testForm.$setSubmitted()"
               type="text">
        <ng-messages for="testForm.testInput.$error" role="alert">
          <ng-message when="required">
            <span>
              required
            </span>
          </ng-message>
        </ng-messages>
      </md-input-container>
    </form>
  </div>
  
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-animate.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-aria.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular-messages.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.6/angular-material.min.js"></script>
</body>
</html>