AngularJS 表单验证

AngularJS Form Validation

今天,我们来看看 Angular 是怎样帮我们做表单验证的。我们会集中讲怎么用 Angular (就像另外一篇文章: Submitting AJAX Forms: The AngularJS Way). 别担心,不需要看那篇,打个广告而已。

我们集中将客户端验证,和怎样用 Angualr 内置表单属性。我们来个快速实现的例子。

Demo

例子

Html:


<div ng-app="validationApp" ng-controller="mainController">
<div class="container">
<div class="row">  

<div class="col-sm-6">
    <!-- =================================================================== -->
    <!-- FORM ============================================================== -->
    <!-- =================================================================== -->

    <form name="userForm" ng-submit="submitForm()" novalidate>

        <!-- NAME -->
        <div class="form-group" ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }">
            <label>Name</label>
            <input type="text" name="name" class="form-control" ng-model="user.name" required>
            <p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">You name is required.</p>
        </div>

        <!-- USERNAME -->
        <div class="form-group" ng-class="{ 'has-error' : userForm.username.$invalid && !userForm.username.$pristine }">
            <label>Username</label>
            <input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
            <p ng-show="userForm.username.$error.minlength" class="help-block">Username is too short.</p>
            <p ng-show="userForm.username.$error.maxlength" class="help-block">Username is too long.</p>
        </div>

        <!-- EMAIL -->
        <div class="form-group" ng-class="{ 'has-error' : userForm.email.$invalid && !userForm.email.$pristine }">
            <label>Email</label>
            <input type="email" name="email" class="form-control" ng-model="user.email">
            <p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
        </div>

        <button type="submit" class="btn btn-primary" ng-disabled="userForm.$invalid">Submit</button>

    </form>
  </div>
  <div class="col-sm-6">
    <!-- =================================================================== -->
    <!-- VALIDATION TABLES ================================================= -->
    <!-- =================================================================== -->    
    <div class="row">
        <div class="col-xs-3">
            <h3>Form</h3>
            <table class="table table-bordered">
                <tbody>
                    <tr>
                        <td ng-class="{ success: userForm.$valid, danger: userForm.$invalid }">Valid</td>
                    </tr>
                    <tr>
                        <td ng-class="{ success: userForm.$pristine, danger: !userForm.$pristine }">Pristine</td>
                    </tr>
                    <tr>
                        <td ng-class="{ success: userForm.$dirty }">Dirty</td>
                    </tr>
                </tbody>
            </table>
        </div>
        <div class="col-xs-3">
            <h3>Name</h3>
            <table class="table table-bordered">
                <tbody>
                    <tr>
                        <td ng-class="{ success: userForm.name.$valid, danger: userForm.name.$invalid }">Valid</td>
                    </tr>
                    <tr>
                        <td ng-class="{ success: userForm.name.$pristine, danger: !userForm.name.$pristine }">Pristine</td>
                    </tr>
                    <tr>
                        <td ng-class="{ success: userForm.name.$dirty }">Dirty</td>
                    </tr>
                </tbody>
            </table>
        </div>
        <div class="col-xs-3">
            <h3>Username</h3>
            <table class="table table-bordered">
                <tbody>
                    <tr>
                        <td ng-class="{ success: userForm.username.$valid, danger: userForm.username.$invalid }">Valid</td>
                    </tr>
                    <tr>
                        <td ng-class="{ success: userForm.username.$pristine, danger: !userForm.username.$pristine }">Pristine</td>
                    </tr>
                    <tr>
                        <td ng-class="{ success: userForm.username.$dirty }">Dirty</td>
                    </tr>
                </tbody>
            </table>
        </div>
        <div class="col-xs-3">
            <h3>Email</h3>
            <table class="table table-bordered">
                <tbody>
                    <tr>
                        <td ng-class="{ success: userForm.email.$valid, danger: userForm.email.$invalid }">Valid</td>
                    </tr>
                    <tr>
                        <td ng-class="{ success: userForm.email.$pristine, danger: !userForm.email.$pristine }">Pristine</td>
                    </tr>
                    <tr>
                        <td ng-class="{ success: userForm.email.$dirty }">Dirty</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</div>
</div>
</div>

CSS:


body { padding-top:30px; }

Javascript:

<!-- lang: js -->
// create angular app
var validationApp = angular.module('validationApp', []);

// create angular controller
validationApp.controller('mainController', function($scope) {

    // function to submit the form after all validation has occurred            
    $scope.submitForm = function() {

        // check to make sure the form is completely valid
        if ($scope.userForm.$valid) {
            alert('our form is amazing');
        }

    };

});

需求

  • Name 必须
  • Username 非必需,最小长度 3, 最大长度 8
  • Email 非必需,不过必须是有效 Email 格式
  • 表单如果未通过验证不能提交
  • 显示必须/或者 Email 格式错误信息
  • 如果提交成功显示信息

好了现在我们知道需要什么了,来看看怎么做。

Angular 表单属性

$valid, $invalid, $pristine, $dirty

Angular 为表单提供了便于验证的属性。它们给我们表单或它的输入的各种信息,并且可应用到表单和输入上。

AngularJS 表单验证_第1张图片

访问 Angular 表单属性

  • 访问表单: <form name>.<angular property>
  • 访问输入: <form name>.<input name>.<angular property>

设置表单

我们用一个简单的表单做演示。

AngularJS 表单验证_第2张图片

我们需要 2个文件:

  • index.html 用于显示表单的代码
  • app.js Angular 应用和控制器(所有代码)

表单代码

index.html


<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <!-- CSS ===================== -->
    <!-- load bootstrap -->
    <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"> 
    <style>
        body    { padding-top:30px; }
    </style>

    <!-- JS ===================== -->
    <!-- load angular -->
    <script src="http://code.angularjs.org/1.2.6/angular.js"></script> 
    <script src="app.js"></script>
</head>

<!-- apply angular app and controller to our body -->
<body ng-app="validationApp" ng-controller="mainController">
<div class="container">
<div class="col-sm-8 col-sm-offset-2">

    <!-- PAGE HEADER -->
    <div class="page-header"><h1>AngularJS Form Validation</h1></div>

    <!-- FORM -->
    <!-- pass in the variable if our form is valid or invalid -->
    <form name="userForm" ng-submit="submitForm(userForm.$valid)" novalidate> <!-- novalidate prevents HTML5 validation since we will be validating ourselves -->

        <!-- NAME -->
        <div class="form-group">
            <label>Name</label>
            <input type="text" name="name" class="form-control" ng-model="name" required>
        </div>

        <!-- USERNAME -->
        <div class="form-group">
            <label>Username</label>
            <input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
        </div>

        <!-- EMAIL -->
        <div class="form-group">
            <label>Email</label>
            <input type="email" name="email" class="form-control" ng-model="email">
        </div>

        <!-- SUBMIT BUTTON -->
        <button type="submit" class="btn btn-primary">Submit</button>

    </form>

</div><!-- col-sm-8 -->
</div><!-- /container -->
</body>
</html>

有几个点值得注意的:

  • novalidate:禁止 HTML5 默认的验证,因为我们会自己实现它(我们的更俊俏)
  • ng-model 应用到输入框,使得我们表单中的数据可以绑定到 Angular 变量上
  • ng-minlengthng-maxlength 会让 username 适用这些验证规则
  • name 设为 required
  • email 设为 type=“email”

验证规则

除了 ng-minlengthng-maxlength 外,Angular 提供了许多验证规则。

下面是 Angular 输入框可用验证属性的一个演示。查看 Angular input directive 获取更多信息。

<!-- lang: js -->
<input
   ng-model="{ string }"
   name="{ string }"
   required
   ng-required="{ boolean }"
   ng-minlength="{ number }"
   ng-maxlength="{ number }"
   ng-pattern="{ string }"
   ng-change="{ string }">
</input>

好了现在我们有了一个简单的表单,下面让我们来创建 Angualr 的 app 和 controller。应用到页面的 ng-appng-controller 上。

Angular App 代码

app.js

<!-- lang: js -->
// app.js
// create angular app
var validationApp = angular.module('validationApp', []);

// create angular controller
validationApp.controller('mainController', function($scope) {

    // function to submit the form after all validation has occurred            
    $scope.submitForm = function(isValid) {

        // check to make sure the form is completely valid
        if (isValid) {
            alert('our form is amazing');
        }

    };

});

禁用 HTML5 验证

novalidate

我们在表单中使用 novalidate ,因为我们要自己处理验证。如果我们让表单自己处理的话,看起来相当丑逼。

AngularJS 表单验证_第3张图片

禁用提交按钮

ng-disabled

好玩的来了。我们现在开始使用 Angular 属性 。首先让我们禁用我们的提交按钮。我们希望我们的表单是 $invalid 的时候让它不可用。

<!-- lang: js -->
<!-- index.html -->
...

    <!-- SUBMIT BUTTON -->
    <button type="submit" class="btn btn-primary" ng-disabled="userForm.$invalid">Submit</button>

...

只需要一丁点代码(ng-disabled),我们的表单按钮就会在表单 $invalid 的时候被禁用。意思就是,我们的 name 输入字段必须有值,email 输入字段必须是可用 email 格式。

显示异常信息

ng-show

如果我们表单设置的规则可用的话,ng-validng-invalid 都会被自动判定。

让我们给我们的输入框都加上异常信息,如果他们是没有 $valid 并且已经被用到了的话(我们肯定不希望在没填入之前就有异常提示啊)。

<!-- lang: js -->
<!-- index.html -->
...

    <!-- NAME -->
    <div class="form-group">
        <label>Name</label>
        <input type="text" name="name" class="form-control" ng-model="name" required>
        <p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">You name is required.</p>
    </div>

    <!-- USERNAME -->
    <div class="form-group">
        <label>Username</label>
        <input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
        <p ng-show="userForm.username.$error.minlength" class="help-block">Username is too short.</p>
        <p ng-show="userForm.username.$error.maxlength" class="help-block">Username is too long.</p>
    </div>

    <!-- EMAIL -->
    <div class="form-group">
        <label>Email</label>
        <input type="email" name="email" class="form-control" ng-model="email">
        <p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
    </div>

...

只需要像这样加几个 ng-show, Angular 就会自动的决定是否显示异常,基于输入框的$invalid$pristine 属性。

AngularJS 表单验证_第4张图片

样式雷

Angular 已经为我们的输入框和表单提供了一些样式,用于显示验证是否通过。可以参考我们文章一开始例子中的样式(ng-validng-invalidng-pristineng-dirty)。

如果你高兴,你也可以用 CSS 定义这些样式。你可以对这些样式做任何事情。甚至是,你如果需要对特殊的情况进行定义的时候,可以基于特殊的要求对它们进行定义。

<!-- lang: js -->
.ng-valid       {  }
.ng-invalid     {  }
.ng-pristine    {  }
.ng-dirty       {  }

/* really specific css rules applied by angular */
.ng-invalid-required        {  }
.ng-invalid-minlength       {  }
.ng-valid-max-length        {  }

追加条件样式

ng-class

因为我们用 Bootsrap,会用到它提供的样式(has-error)。这让我们可以在 form-group 的边框加上颜色,对用户更加友好。

ng-class 允许我们基于异常来添加样式。比如说,如果一个输入框是 $invalid 并且不 pristine 的时候,我们给 form-group 加上 has-error 样式。

实现的方式是 ng-class="{ <class-you-want> : <expression to be evaluated > }"。更多信息可以查看 Angular ngClass docs。

<!-- lang: js -->
<!-- index.html -->
...

    <!-- NAME -->
    <div class="form-group" ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }">
        <label>Name</label>
        <input type="text" name="name" class="form-control" ng-model="user.name" required>
        <p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">You name is required.</p>
    </div>

    <!-- USERNAME -->
    <div class="form-group" ng-class="{ 'has-error' : userForm.username.$invalid && !userForm.username.$pristine }">
        <label>Username</label>
        <input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
        <p ng-show="userForm.username.$error.minlength" class="help-block">Username is too short.</p>
        <p ng-show="userForm.username.$error.maxlength" class="help-block">Username is too long.</p>
    </div>

    <!-- EMAIL -->
    <div class="form-group" ng-class="{ 'has-error' : userForm.email.$invalid && !userForm.email.$pristine }">
        <label>Email</label>
        <input type="email" name="email" class="form-control" ng-model="user.email">
        <p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
    </div>

...

于是,我们的表单正确套用了 Bootstrap 的异常样式。

AngularJS 表单验证_第5张图片

在提交表单之后显示异常

有时候在用户输入的时候显示异常是不好的。现在的例子是当用户在表单中输入的时候,立刻反映出来。这归功于 Angular 牛逼的数据绑定功能。但在表单验证的时候,所有的改变都立刻反映,倒可以算是一个缺点了。

对于这种场景,比如你只希望在提交表单之后显示异常,你需要对上面的代码做一些改变。

  • 把提交按钮的 ng-disabled 属性去掉,因为我们希望用户在即使没有完全验证的情况下,也可以提交表单。
  • 你要在表单提交之后加一个变量。在你的 submitForm() 方法中,加上 $scope.submitted = true;。一旦表单被提交,变量立刻就被设置为 true 了。
  • 把判断异常的规则从 ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }" 改为 ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine && submitted }"。这保证了异常只有在表单被提交之后才会显示。你应该需要对所有的 ng-classng-show 都做一下同样的设置

现在表单只有在 submitted 变量是 true 的时候才会显示异常了。

在点击输入框外后显示异常

点击输入框外后显示异常(也就是所谓的blur)比提交之后显示异常复杂点。当 blur 的时候检查验证是一个自定义指令。指令允许你操作 DOM。

我们把这个话题分开写了一篇教程。这里还有其他的一些关于创建处理 blur 的自定义指令的教程:

  • http://coding-issues.blogspot.in/2013/10/angularjs-blur-directive.html
  • http://blog.ejci.net/2013/08/06/dealing-with-focus-and-blur-in-angularjs-directives/
  • http://plnkr.co/edit/Xfr7X6JXPhY9lFL3hnOw?p=preview

总结

现在一旦我们把我们的信息都填对了,我们的表单提交按钮就会被激活,一旦我们提交了我们的表单,我们可以看到弹出框显示这样的信息。

AngularJS 表单验证_第6张图片

罗列一下我们现在有的功能:

  • 输入验证
  • 表单异常
  • 自定义样式
  • 自动激活/禁止表单
  • 自定义规则

如你所见,用 Angular 来做客户端的表单验证非常简单。

进阶

标准情况,实现点击输入框外后显示异常并不是件简单的事情。 Angular 团队已经认识到了这点,并且他们说他们计划会追加更多的状态来处理,比如说 form.submittedinput.$visitedinput.$blurred,或者是 input.$touched。这里有些关于表单认证的资源:

  • Github Issue
  • ngForm Module Ideas

希望越快越好,我们能够在应用的各种情况下,更简单的验证表单。

你可能感兴趣的:(AngularJS,validation,Forms)