5

我正在编写一个需要 ngModel 并添加格式化程序和解析器来操作值的指令。它工作得很好,但由于操作取决于我必须 $watch 的外部数据,我正在寻找一种方法来更新这个手表的模型值。我试图打电话$setViewValue但没有任何反应(因为 $viewValue 没有改变??)。

在以下简单示例中,对“因子”的更改不会更新模型值:

angular.module('app', []).directive('multiply', multiplyDirective);

function multiplyDirective() {
    return {
        restrict: 'A',
        require: 'ngModel',
        scope: {
            factor: '=multiply'
        },
        link: function(scope, elem, attr, ngModel) {

            ngModel.$formatters.push(function (value) {
                return value / scope.factor;
            });

            ngModel.$parsers.push(function (value) {
                return value * scope.factor;
            });

            scope.$watch('factor', function () {
               // how to run the parsers pipeline to update modelvalue?
               ngModel.$setViewValue(ngModel.$viewValue);
            });
        }
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.min.js"></script>


<body ng-app ng-init="factor = 1; value = 1">
  <input type="number" ng-model="value" multiply="factor" /> x
  <input type="number" ng-model="factor" />
  = {{ value }}
</body>

编辑:如果我调用内部$$parseAndValidate方法,它会起作用,但我想知道是否有公共 API 来强制更新。

编辑:我发现,ngModel.$setViewValue(ngModel.$viewValue);1.3.0. 使用1.2.x代码有效!

4

3 回答 3

1

有点晚了,但我已经描述了如何在这里做到这一点。这适用于 AngularJS 1.6.x

基本上你可以$parsers pipeline通过使用来触发$setViewValue().

下面是一个代码片段,它允许您通过“劫持”$parsers 管道以编程方式将 ngModel 设置为您喜欢的任何内容。这是使用闭包完成的。

使用这样的闭包设置 $parser:

const hijack = {trigger: false; model: null};
modelCtrl.$parsers.push( val => {
   if (hijack.trigger){
        hijack.trigger = false;
        return hijack.model;
   }
   else { 
      // .. do something else ...
   })

然后对于(重新)设置模型,您需要通过更改$viewValuewith来触发管道modelCtrl.$setViewValue('newViewValue')。(是的,新视图值必须与当前值不同)。

const $setModelValue = function(model){
    // trigger the hijack and pass along your new model
    hijack.trigger = true;
    hijack.model = model; 
    // assuming you have some logic in getViewValue to output a viewValue string
    modelCtrl.$setViewValue( "some new view value" ); 
    }
于 2017-06-21T08:34:37.710 回答
0

您的指令根本没有加载。您需要将模块名称提供给 ng-app like <body ng-app="app">。之后ngModel.$setViewValue(ngModel.$viewValue)只要修改因子就调用。

angular.module('app', []).directive('multiply', multiplyDirective);

function multiplyDirective() {
    return {
        restrict: 'A',
        require: 'ngModel',
        scope: {
            factor: '=multiply'
        },
        link: function(scope, elem, attr, ngModel) {

            ngModel.$formatters.push(function (value) {
                return value / scope.factor;
            });

            ngModel.$parsers.push(function (value) {
                return value * scope.factor
            });

            scope.$watch('factor', function () {
               // how to run the parsers pipeline to update modelvalue?
              ngModel.$setViewValue(ngModel.$viewValue);
             
            });
        }
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>


<body ng-app="app" ng-init="factor = 1; value = 1">
  <input type="number" ng-model="value" multiply="factor" /> x
  <input type="number" ng-model="factor" />
  = {{ value }}
</body>

于 2014-12-19T14:40:43.010 回答
0

从 v1.3.18 的来源,我看不到公共 api。管道来自$$parseAndValidate方法,该方法也从$commitViewValue 调用(需要提交/设置不同的值,否则它将返回

于 2015-08-21T21:34:59.590 回答