AngularJS 如何强制输入在模糊时重新渲染 [英] AngularJS how to force an input to be re-rendered on blur

查看:22
本文介绍了AngularJS 如何强制输入在模糊时重新渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have some custom validation code, which includes a $formatter. (I store currency in pence for correctness, but display in pounds.pence.)

如果用户在输入中键入10"(这是一个有效值),则在移动到下一个字段后,输入仍会显示10".

If the user types '10' into the input (which is a valid value), the input remains displaying '10' after they move to the next field.

为了一致性,我希望它显示 10.00.

I would like it to display 10.00 for consistency.

如果模型将值更改为 1000,则格式化程序将使该字段显示为10.00".

If the model changed the value to 1000, then the formatter would make the field display '10.00'.

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

I would like the formatter to run on field.blur() (so long as the input is valid).

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

My problem is that if I change the model value from 10 to 10, there is understandably no change, and so the field is not re-rendered.

代码:

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); 
      });
    }
  };
});

附言这与 Angular 内置的货币"无关.

P.S. This has nothing to do with Angular's built-in 'currency'.

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

Update: I've added a 'renderOnBlur' directive, as per Andy's answer. It gets called, but calling the render method does not re-render the input. i.e. '10' stays as '10', rather than changing to '10.00' as desired.

(当这些字段中的模型值发生变化时,它们会正确呈现为小数点后两位.)

(When the model value changes in these fields, they are correctly rendered with the 2 decimal places.)

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

The page which Andy mentions http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController says that you have to implement $render yourself. This seems odd, as the inputs are already rendered correctly when the model value changes.

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();
            });
        }
    };  
});

附言我不知道 restrict: 'A', 做了什么——这是最糟糕的真正的货物崇拜编程.require: 'ngModel', 似乎是填充 ctrl 参数所必需的.

P.S. I have no idea what restrict: 'A', does - it's true cargo-cult programming at its worst. The require: 'ngModel', seems necessary to populate the ctrl parameter.

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

Inspired by the answer from @Dan Doyen, I rewrote it as:

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 的回答那样重复格式化程序代码.

This has the benefit of being generic for any $formatter, rather than repeating the formatter code as in Dan's answer.

推荐答案

您的控制器的 $modelValue 正在正确更新,但是,由于模糊事件发生在 angular 之外,您的 $viewValue 似乎不是.这个怎么样?

Your controller's $modelValue is being updated properly, however, but since the blur event is happening outside of angular, it seems your $viewValue is not. How about this?

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

这篇关于AngularJS 如何强制输入在模糊时重新渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆