AngularJS 使用 ngMessages 从控制器设置表单值

AngularJS set form value from controller with ngMessages

我尝试在 angular 1.5.9 中使用表单,但无法找到满足以下要求的方法:

  1. 从控制器访问表单数据(绑定controllerAs
  2. 不要使用$scope绑定表单
  3. 能够从控制器设置默认值
  4. 能够从控制器更改值
  5. 能够从控制器访问数据
  6. 使用 ngMessages 进行验证

我做了一个注释 jsbin 来说明问题和我尝试过的方法,你可以在这里找到它:http://jsbin.com/guzejelula/edit?html,js,output

除了第 4 个之外,这里的每个要求都在 jsbin 中得到满足,说明为:

this.setLastName = function(name) { 
    // When doing this while the field is empty, the "required"
    // error disappear but the input stays empty.
    this.userForm.lastName.$setViewValue(name);
    this.userForm.lastName.$validate();  
}

我错过了什么?

您需要告诉刚刚更改的视图(输入)呈现自身,以便更改模型值(以便新值显示在表单字段中)。

angular.element('your element id').controller('ngModel').$render()

据我所知,我认为您绑定的模型不正确。

$ctrl.userForm 是您的表单控制器实例。 ngModel 上的 "name" 属性将表单控件(输入)实例公开给表单控制器实例。所以,$ctrl.userForm.lastName 不会是原始模型值,它将是一个具有 ngModelController 函数的对象。

为了pre-populate表单控制器正确,确保ng-model表达式有正确的初始值。目前,您的 ng-model 绑定到 $scope.lastName。这就是为什么它呈现为空而不是 "toto." 要修复它,您可以将 $scope.lastName = "toto" 添加到您的控制器,但是由于您要避免使用 $scope,只需定义 this.lastName = 'toto' 并使用 ng-model="$ctrl.lastName".

从按钮中,您只需执行 this.lastName = name。无需自己调用 $render$validate,因为 Angular 会代表您执行此操作,因为它会检测到模型值的变化。

如果有帮助,我刚刚写了一个 article 来了解 ngModelController 中发生的事情,如果您有兴趣的话。

希望对您有所帮助!

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

app.controller('DemoCtrl', function() {
  
  /**
   * Here I would like to set a defaut state form the form.
   * 
   * This object will be replaced by the FormController instance
   * as defined in the view by "<form name="$ctrl.userForm">" 
   * with no regards for its current content.
   */

  this.lastName = 'toto';
  this.formResults = {};
  
  /**
   * I would like to set the value of one or multiple fields
   * in the controller.
   * Here I try to set "lastName" with no success.
   *
   * I excepted something like:
   * this.userForm.setValues({
   *   lastName : 'Doe', 
   *   firstName: 'John'
   * });
   * 
   * or 
   *
   * this.userForm.setValue('lastName', 'value here');
   *
   * ...
   */
  this.setLastName = function(name) { 
    // When doing this while the field is empty, the "required"
    // error disappear but the input stays empty.
    this.lastName = name;
  }
  
  
  /**
   * Here a clean way to extract current values of the form would be handy..
   * Something like : 
   * this.userForm.getValues(); 
   */
  this.submit = function(form){
    this.formResults = {};
    if (form.$valid) {
      var values = {};
      angular.forEach(form, function (value, key) {
        if (typeof(value) === 'object' && value.hasOwnProperty('$modelValue')) {
            values[key] = value.$modelValue;
        } 
      });
      this.formResults = values;
    }
  };
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Angular JS</title>
</head>
<body ng-app="jsbin">
  <div ng-controller="DemoCtrl as $ctrl">
    
    <form name="$ctrl.userForm" novalidate>
      <label>Last Name:</label>
      <input name="lastName" ng-model="$ctrl.lastName" required="" minlength="2" type="text">
      <ng-messages for="$ctrl.userForm.lastName.$error">
          <ng-message when="minlength">Too small!</ng-message>
          <ng-message when="required">Required!</ng-message>
      </ng-messages>
      <button ng-click="$ctrl.submit($ctrl.userForm)">Submit</button>
    </form>
    
    <p>
      <button ng-click="$ctrl.setLastName('Test')">Set value to "lastName"</button>
    </p>
    
    <h2>Results</h2>
    {{$ctrl.formResults|json}}

  </div>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.9/angular.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular-messages/1.5.9/angular-messages.js"></script>
</body>
</html>