一尘不染

AngularJS如何在模糊时强制重新渲染输入

angularjs

我有一些自定义验证代码,其中包括$ formatter。(为了正确起见,我将货币以便士存储,但以磅为便士显示。)

如果用户在输入中键入“ 10”(这是一个有效值),则输入移至下一个字段后,输入仍显示“ 10”。

我希望它显示10.00以保持一致性。

如果模型将值更改为1000,那么格式化程序将使该字段显示为“ 10.00”。

我希望格式化程序在field.blur()上运行(只要输入有效)。

我的问题是,如果将模型值从10更改为10,可以理解的是没有更改,因此该字段不会重新呈现。

码:

var CURRENCY_REGEXP = /^\-?\d+(\.?\d?\d?)?$/;
app.directive('currency', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        if (CURRENCY_REGEXP.test(viewValue)) {
          // it is valid
          ctrl.$setValidity('currency', true);
          console.log("valid");
          return viewValue * 100;
        } else if (viewValue === '') {
          return 0;
        } else {
          // it is invalid, return undefined (no model update)
          ctrl.$setValidity('currency', false);
          console.log("invalid");
          return undefined;
        }
      });
      ctrl.$formatters.push(function(modelValue) {
         if (modelValue === 0) { // we're using integer pence, so this is safe
             return '';
         }
         return (modelValue / 100).toFixed(2); 
      });
    }
  };
});

PS这与Angular的内置“货币”无关。


更新:根据安迪的回答,我添加了一个“ renderOnBlur”指令。它被调用,但是调用render方法不会重新渲染输入。即“ 10”保持为“
10”,而不是根据需要更改为“ 10.00”。

(当模型值在这些字段中更改时,它们将正确显示为小数点后两位。)

Andy提到的页面http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController说您必须实现$render自己。这似乎很奇怪,因为当模型值更改时,输入已经正确呈现。

app.directive('renderOnBlur', function() {
    return {
        require: 'ngModel',
        restrict: 'A',
        link: function(scope, elm, attrs, ctrl) {
            elm.bind('blur', function() {
                console.log('rendering ctrl', ctrl);
                ctrl.$render();
            });
        }
    };  
});

PS:我不知道该怎么办restrict: 'A',-在最糟糕的情况下,这是真正的“货神教”式编程。该require: 'ngModel',填充似乎是必要ctrl的参数。


受@Dan Doyen的回答启发,我将其重写为:

app.directive('renderOnBlur', function() {
    return {
        require: 'ngModel',
        restrict: 'A',
        link: function(scope, elm, attrs, ctrl) {
            elm.bind('blur', function() {
                var viewValue = ctrl.$modelValue;
                for (var i in ctrl.$formatters) {
                    viewValue = ctrl.$formatters[i](viewValue);
                }
                ctrl.$viewValue = viewValue;
                ctrl.$render();
            });
        }
    };  
});

这具有对任何$ formatter通用的好处,而不是像Dan的回答那样重复格式化程序代码。


阅读 237

收藏
2020-07-04

共1个答案

一尘不染

您的控制器的$ modelValue正在正确更新,但是,由于blur事件发生在angular之外,因此您的$ viewValue似乎没有。这个怎么样?

 elm.bind('blur', function() {
       ctrl.$viewValue = (ctrl.$modelValue / 100).toFixed(2);
       ctrl.$render();
 });
2020-07-04