使用来自控制器的ngModel setViewValue

Use ngModel setViewValue from controller

本文关键字:ngModel setViewValue 控制器      更新时间:2023-09-26

我将一个值数组绑定到一些输入元素。在输入元素上有一些指令,用来设置$解析器、$格式化器和$验证器。控制器不应该关心从viewValue到modelValue的管道。

视图:

  <ul>
    <li ng-repeat="value in main.values">
      <input ng-model="value.v" twice /> {{value.v}}
    </li>
  </ul>

控制器/指令:

function MainController($scope) {
  this.values = [
    {v: 1}, {v: 2}, {v: 3}
  ];  
}
function twice() {
  return {
    require: 'ngModel',
    link: function(scope, elem, attr, ngModel) {
      ngModel.$formatters.push(function(x) { return 2 * x });
      ngModel.$parsers.push(function(x) { return 0.5 * x });
    }
  }  
}

我想实现一个拷贝&粘贴功能。所有输入元素中的值都应该从剪贴板数据中重写。因此,控制器实现了一个函数,该函数解析剪贴板数据并为每个输入元素设置值。剪贴板中的值是视图值。因为控制器不知道如何从这些视图值中计算模型值,所以它必须使用来自'ngModelController'的'$parsers'管道。我如何实现MainController.paste()来设置每个输入元素的视图值?

编辑

我目前解决了实际问题(见注释)与列表元素上的指令。http://plnkr.co/edit/9c2q2X?p=preview

function pasteValues() {
  return {
    link: function(scope, elem, attr, ngModel) {
      elem.on('paste', function($event) {
        var data = $event.clipboardData || window.clipboardData;
        var text = data.getData('Text');
        var values = text.split(' ');
        var inputs = elem.find('input');
        if (values.length === inputs.length) {
          for(var i = 0, e = values.length; i != e; ++i) {
            var input = inputs[i];
            var ngModel = angular.element(input).controller('ngModel');
            ngModel.$setViewValue(values[i]);
            input.value = values[i];
          }
          $event.preventDefault();
        }
      })
    }
  }  
}

我发现了两种可能的解决方案(在写问题的时候:-))。http://plnkr.co/edit/ZNfYKTvSf6coGsohRlot?p=preview

1

第一个不是真正的角方式,因为控制器必须知道DOM结构。但它很简单,不需要额外的绑定和手表。为了设置视图值,它使用angular.element.controller()方法来检索每个输入元素的ngModelController。

function MainController($scope) {
  this.paste = function() {
    var value = this.pasteValue;
    var inputs = angular.element(document.getElementById('values')).find('input');
    angular.forEach(inputs, function(input) {
      var ngModel = angular.element(input).controller('ngModel');
      ngModel.$setViewValue(value);
      input.value = value;
    });
  };
}
2

第二个解决方案是更有棱角的方式,它使用了一个额外的指令来监视粘贴数据。

function setView() {
  return {
    require: 'ngModel',
    scope: {
      setView : '='
    },
    link: function(scope, elem, attr, ngModel) {
      scope.$watch('setView', function(newValue) {
        if (angular.isDefined(newValue)) {
          elem.val(newValue);
          ngModel.$setViewValue(newValue);
        }
      })
    }
  }  
}
function MainController($scope) {
  this.paste = function() {
    var value = this.pasteValue;
    this.values.forEach(function(v) { v.i = value });
  };
}
视图:

<ul>
    <li ng-repeat="value in main.values">
      <input ng-model="value.v" twice set-view="value.i"/> {{value.i}}({{value.v}})
    </li>
</ul>