• Angularjs-Forms(表单)


    点击查看AngularJS系列目录
    转载请注明出处:http://www.cnblogs.com/leosx/



    Angular表单

    input, select, textarea控件都是给用户输入数据用的。窗体和控件提都提供了验证服务,使得在用户输入了无效数据的情况下,提交表单之前就可以得到知道。这样的验证远远比只在服务端进行验证好得多,因为在前端验证,用户可以得到很好的用户输入错误的反馈!提高用户体验。请记住,在客户端进行验证是用户体验的非常重要的组成部分。但是它很容易就可以被篡改,所以我们是不能信赖前端验证的,后端依旧得进行验证。

    一个简单的表单

    文件一:index.html

    <div ng-controller="ExampleController">
      <form novalidate class="simple-form">
        Name: <input type="text" ng-model="user.name" /><br />
        E-mail: <input type="email" ng-model="user.email" /><br />
        Gender: <input type="radio" ng-model="user.gender" value="male" />male
        <input type="radio" ng-model="user.gender" value="female" />female<br />
        <input type="button" ng-click="reset()" value="Reset" />
        <input type="submit" ng-click="update(user)" value="Save" />
      </form>
      <pre>user = {{user | json}}</pre>
      <pre>master = {{master | json}}</pre>
    </div>
    
    <script>
      angular.module('formExample', [])
        .controller('ExampleController', ['$scope', function($scope) {
          $scope.master = {};
    
          $scope.update = function(user) {
            $scope.master = angular.copy(user);
          };
    
          $scope.reset = function() {
            $scope.user = angular.copy($scope.master);
          };
    
          $scope.reset();
        }]);
    </script>

    效果图:

    image

    当点击Reset按钮的时候,就会把user对象给重置为原来保存的对象。

    请注意:novalidate 用来禁用掉原生的浏览器表单验证。如果验证不通过,那么ngModel 所绑定的model的对应值是不会改变的。

    样式的使用

    使用样式,我们可以更好的控制表单控件,例如:ngModel 指令就为对应的元素增加了如下样式:

    1、ng-valid: 模型(model)验证通过

    2、ng-invalid: 模型(model)验证失败

    3、ng-valid-[key]: 通过$setValidity增加的验证通过的密匙()

    4、ng-invalid-[key]: 通过$setValidity增加的验证失败的密匙

    5、ng-pristine: 还没有与controller进行互动。

    6、ng-dirty: 控制器与之有互动

    7、ng-touched: 已经失去控制

    8、ng-untouched: 还未失去控制

    9、ng-pending: 异步验证($asyncValidators )还未结束

    下面的示例使用CSS来显示每个表单控件的有效性。例子中,user.nameuser.email 是必须的,当失去焦点时,会进行验证,如果验证不通过,那么背景色会变成红色的。这确保了用户不会忽略掉错误,知道验证通过了,才会同步到controller的model中去。

    文件一:index.html

    <div ng-controller="ExampleController">
      <form novalidate class="css-form">
        Name: <input type="text" ng-model="user.name" required /><br />
        E-mail: <input type="email" ng-model="user.email" required /><br />
        Gender: <input type="radio" ng-model="user.gender" value="male" />male
        <input type="radio" ng-model="user.gender" value="female" />female<br />
        <input type="button" ng-click="reset()" value="Reset" />
        <input type="submit" ng-click="update(user)" value="Save" />
      </form>
      <pre>user = {{user | json}}</pre>
      <pre>master = {{master | json}}</pre>
    </div>
    
    <style type="text/css">
      .css-form input.ng-invalid.ng-touched {
        background-color: #FA787E;
      }
    
      .css-form input.ng-valid.ng-touched {
        background-color: #78FA89;
      }
    </style>
    
    <script>
      angular.module('formExample', [])
        .controller('ExampleController', ['$scope', function($scope) {
          $scope.master = {};
    
          $scope.update = function(user) {
            $scope.master = angular.copy(user);
          };
    
          $scope.reset = function() {
            $scope.user = angular.copy($scope.master);
          };
    
          $scope.reset();
        }]);
    </script>
    效果图:
    image
    可以看到,用户名name验证通过了,但是邮件验证失败,未通过。

    绑定表单状态和控件状态

    Angular的一个表单就是一个FormController的实例对象。表单的实例对象可以使用name属性有选择的发布到scope上去。

    同样的,input控件都会具有一个NgModelController的实例ngModel 指令。这种input控件(表单实例)的实例可以通过name 属性所对应的控件上,再发布一个属性。

    这使我们能够扩展上面的例子有以下功能:

    1、如果有自定义错误,那么用户和控件交互后,会被触发判断,如果有错,将会立即显示提示消息(如果设置了$touched,那么手机上触摸也会执行)。

    2、当用户点击submit按钮($submitted)的时候,即使之前没有执行交互,那么一样会触发自定义验证,并显示错误消息。

    文件一:index.html

    <div ng-controller="ExampleController">
      <form name="form" class="css-form" novalidate>
        Name:
        <input type="text" ng-model="user.name" name="uName" required="" />
        <br />
        <div ng-show="form.$submitted || form.uName.$touched">
          <div ng-show="form.uName.$error.required">Tell us your name.</div>
        </div>
    
        E-mail:
        <input type="email" ng-model="user.email" name="uEmail" required="" />
        <br />
        <div ng-show="form.$submitted || form.uEmail.$touched">
          <span ng-show="form.uEmail.$error.required">Tell us your email.</span>
          <span ng-show="form.uEmail.$error.email">This is not a valid email.</span>
        </div>
    
        Gender:
        <input type="radio" ng-model="user.gender" value="male" />male
        <input type="radio" ng-model="user.gender" value="female" />female
        <br />
        <input type="checkbox" ng-model="user.agree" name="userAgree" required="" />
    
        I agree:
        <input ng-show="user.agree" type="text" ng-model="user.agreeSign" required="" />
        <br />
        <div ng-show="form.$submitted || form.userAgree.$touched">
          <div ng-show="!user.agree || !user.agreeSign">Please agree and sign.</div>
        </div>
    
        <input type="button" ng-click="reset(form)" value="Reset" />
        <input type="submit" ng-click="update(user)" value="Save" />
      </form>
      <pre>user = {{user | json}}</pre>
      <pre>master = {{master | json}}</pre>
    </div>

    文件二:script.js

    angular.module('formExample', [])
    .controller('ExampleController', ['$scope', function($scope) {
      $scope.master = {};
    
      $scope.update = function(user) {
        $scope.master = angular.copy(user);
      };
    
      $scope.reset = function(form) {
        if (form) {
          form.$setPristine();
          form.$setUntouched();
        }
        $scope.user = angular.copy($scope.master);
      };
    
      $scope.reset();
    }]);

    效果图:

    image

    自定义模型的更新触发时机(WPF中的更新时间)

    默认情况下,任何内容的改变将触发表单验证和model的更新。你可以通过ngModelOptions指令绑定到一个事件集合中来重写触发的时间,例如:ng-model-options="{ updateOn: 'blur' }" 将会在控件失去焦点后执行表单验证和更新Model。你可以使用空格来分割多个事件的触发验证和更新的时间。例如:ng-model-options="{ updateOn: 'mousedown blur' }"

    forms-update-on-blur

    如果你想更改默认的触发时机,你可以使用"default" 来指定:

    例如:ng-model-options="{ updateOn: 'default blur' }"

    下面的例子展示了如何重写更新时机。修改触发时机为失去焦点时执行触发验证和更新。

    文件一:index.html

    <div ng-controller="ExampleController">
      <form>
        Name:
        <input type="text" ng-model="user.name" ng-model-options="{ updateOn: 'blur' }" /><br />
        Other data:
        <input type="text" ng-model="user.data" /><br />
      </form>
      <pre>username = "{{user.name}}"</pre>
      <pre>userdata = "{{user.data}}"</pre>
    </div>

    文件二:script.js

    angular.module('customTriggerExample', [])
    .controller('ExampleController', ['$scope', function($scope) {
      $scope.user = {};
    }]);

    效果演示:

    leosx001

    延迟更新和验证时间

    你可以使用ngModelOptions 指令来延迟Model的验证和更新时间。这种延迟同样适用于parsers(解析器)、validators(验证器)、model标签(eg:$dirty 或者 $pristine)

    例如:ng-model-options="{ debounce: 500 }" 会在出发之后延迟500毫秒再执行验证和更新model。

    forms-debounce

    如果自定义的触发器被使用,那么我们可以使用debounce来为每个自定义的触发器指定延迟时间。

    例如:ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"

    如果这些属性被加到一个元素上去,那么这种机制会应用到这个元素下的所有子元素下,也就是会继承这种机制,除非子元素重写了这种机制。

    我们来看下面的例子,验证动作和model的更新将会在最后一次更改input内容250毫秒后执行。

    文件一:index.html

    <div ng-controller="ExampleController">
      <form>
        Name:
        <input type="text" ng-model="user.name" ng-model-options="{ debounce: 250 }" /><br />
      </form>
      <pre>username = "{{user.name}}"</pre>
    </div>

    文件二:script.js

    angular.module('debounceExample', [])
    .controller('ExampleController', ['$scope', function($scope) {
      $scope.user = {};
    }]);

    效果图:

    leosx002

    自定义验证

    Angular提供了对HTML5最常用的表单控件的实现(text, number, url, email, date, radio, checkbox),同样的,相同的验证也有被重写:(required, pattern, minlength, maxlength, min, max).

    通过自定义指令,你可以通过对ngModelController对象的$validators 实例(也就是ng-model指令)添加自己的验证功能,在下面的示例中,我们会用到。

    $validators 对象上的每一个验证函数都将modelValueviewValue 做为参数。接着Angular会调用$setValidity方法,它会返回(true: valid【验证通过】, false: invalid【验证失败】)。验证函数会在每次输入改变的时候执行($setViewValue 被调用),或者触发时机被修改了,一样会触发验证。当分别成功执行了$parsers$formatters方法后,会执行验证(Validation),如果验证错误,那么会把错误信息保存到ngModelController.$error对象中去。

    此外,$asyncValidators 对象可以进行异步验证,它就相当于使用$http 去调用后台执行验证。这个验证方法必须承诺当验证通过时,返回resolved;当验证失败时,返回rejected ;执行异步验证的结果将会保存到ngModelController.$pending中去。

    下面的例子中,我们创建了两个指令:

    1、integer 指令用于验证输入的值是否是数字(int类型),例如:1.23 将会验证失败,因为它有小数部分。注意,我们这里验证的是view(视图)中的控件的输入值,并不是控件对应的model的值。因为只有成功的执行了$parsers方法后,才会将数据更新到model的对应属性中去。

    2、username 指令用于异步验证用户名。如果该用户已经存在,那么会给出提示!这里,我们使用$q来模拟从服务器验证。

    文件一:index.html

    <form name="form" class="css-form" novalidate>
      <div>
        Size (integer 0 - 10):
        <input type="number" ng-model="size" name="size"
               min="0" max="10" integer />{{size}}<br />
        <span ng-show="form.size.$error.integer">The value is not a valid integer!</span>
        <span ng-show="form.size.$error.min || form.size.$error.max">
          The value must be in range 0 to 10!</span>
      </div>
    
      <div>
        Username:
        <input type="text" ng-model="name" name="name" username />{{name}}<br />
        <span ng-show="form.name.$pending.username">Checking if this name is available...</span>
        <span ng-show="form.name.$error.username">This username is already taken!</span>
      </div>
    
    </form>

    文件二:script.js

    var app = angular.module('form-example1', []);
    
    var INTEGER_REGEXP = /^-?d+$/;
    app.directive('integer', function() {
      return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl) {
          ctrl.$validators.integer = function(modelValue, viewValue) {
            if (ctrl.$isEmpty(modelValue)) {
              // consider empty models to be valid
              return true;
            }
    
            if (INTEGER_REGEXP.test(viewValue)) {
              // it is valid
              return true;
            }
    
            // it is invalid
            return false;
          };
        }
      };
    });
    
    app.directive('username', function($q, $timeout) {
      return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl) {
          var usernames = ['Jim', 'John', 'Jill', 'Jackie'];
    
          ctrl.$asyncValidators.username = function(modelValue, viewValue) {
    
            if (ctrl.$isEmpty(modelValue)) {
              // consider empty model valid
              return $q.when();
            }
    
            var def = $q.defer();
    
            $timeout(function() {
              // Mock a delayed response
              if (usernames.indexOf(modelValue) === -1) {
                // The username is available
                def.resolve();
              } else {
                def.reject();
              }
    
            }, 2000);
    
            return def.promise;
          };
        }
      };
    });

    效果图:

    leosx003

    修改内置的验证机制

    自从Angular使用了$validators来进行校验数据,你就可以很轻松的替换掉默认的数据验证方式。下面的例子中,我们使用自定义的指令重写了表单中邮件input[email] 的验证方式。注意,你也可以使用ng-pattern 指令来进一步限制验证。

    文件一:index.html

    <form name="form" class="css-form" novalidate>
      <div>
        Overwritten Email:
        <input type="email" ng-model="myEmail" overwrite-email name="overwrittenEmail" />
        <span ng-show="form.overwrittenEmail.$error.email">This email format is invalid!</span><br>
        Model: {{myEmail}}
        </div>
    </form>

    文件二:script.js

    var app = angular.module('form-example-modify-validators', []);
    
    app.directive('overwriteEmail', function() {
      var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example.com$/i;
    
      return {
        require: 'ngModel',
        restrict: '',
        link: function(scope, elm, attrs, ctrl) {
          // only apply the validator if ngModel is present and Angular has added the email validator
          if (ctrl && ctrl.$validators.email) {
    
            // this will overwrite the default Angular email validator
            ctrl.$validators.email = function(modelValue) {
              return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue);
            };
          }
        }
      };
    });

    效果图:

    leosx005

    实现自定义表单控件(使用 ngModel)

    Angular实现了基本的HTML表单控件(input, select, textarea),他们可以满足大部分需求了。为了更好的灵活性,你也可以通过指令来自定义属于自己的表单控件。

    为了使得自定义控件可以很好的和ngModel 指令进行数据的双向通信,你需要:

    1、实现$render 方法,它负责在NgModelController.$formatters后,呈现数据。

    2、调用$setViewValue 方法,当用户与控件进行交互,需要进行model的更新时。这个动作通常在一个DOM事件监听器里完成的。

    点击这里,查看关于$compileProvider.directive 的更多信息。

    下面的例子展示了如何为contentEditable元素增加的数据的双向绑定。

    文件一:index.html

    <div contentEditable="true" ng-model="content" title="Click to edit">Some</div>
    <pre>model = {{content}}</pre>
    
    <style type="text/css">
      div[contentEditable] {
        cursor: pointer;
        background-color: #D0D0D0;
      }
    </style>

    文件二:script.js

    angular.module('form-example2', []).directive('contenteditable', function() {
      return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl) {
          // view -> model
          elm.on('blur', function() {
            ctrl.$setViewValue(elm.html());
          });
    
          // model -> view
          ctrl.$render = function() {
            elm.html(ctrl.$viewValue);
          };
    
          // load init value from DOM
          ctrl.$setViewValue(elm.html());
        }
      };
    });

    效果图:

    leosx008

  • 相关阅读:
    转载(腾讯云社区)——详解django-apscheduler的使用方法
    pipenv——python包管理工具
    xx系统需求进度02
    xx系统需求进度01
    Hbase简介
    第七周总结
    《软件需求十步走》阅读笔记一
    第六周总结
    HDFS
    金字塔表达方法
  • 原文地址:https://www.cnblogs.com/leosx/p/4911784.html
Copyright © 2020-2023  润新知