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

AngularJS如何强制在模糊上重新渲染输入,angularjs,Angularjs,我有一些自定义验证代码,其中包括$formatter。(为了正确起见,我将货币存储为便士,但显示为英镑。便士。) 如果用户在输入中键入“10”(这是一个有效值),则在移动到下一个字段后,输入仍显示“10” 我想它显示10.00的一致性 如果模型将值更改为1000,则格式化程序将使字段显示“10.00” 我希望格式化程序在field.blur()上运行(只要输入有效) 我的问题是,如果我将模型值从10更改为10,则不存在任何更改,因此不会重新渲染字段 代码: 另外,这与Angular的内置“货币”

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

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

我想它显示10.00的一致性

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

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

我的问题是,如果我将模型值从10更改为10,则不存在任何更改,因此不会重新渲染字段

代码:

另外,这与Angular的内置“货币”无关


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

(当这些字段中的模型值发生更改时,将使用小数点后2位正确渲染这些字段。)

Andy提到的页面说您必须自己实现
$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();
            });
        }
    };  
});
另外,我不知道“限制:'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回答中的格式化程序代码。

尝试使用ctrl.$render on blur

elm.bind('blur',function(){ctrl.$render()})


请参见。

10.00==10
true

a=10.00

console.log(a)
10

.00在javascript上没有任何意义,因此您的10.00将变成10.00


我建议将该值设置为字符串,以便可以创建所需的格式。不过,控制器的$modelValue正在正确更新,但由于模糊事件发生在angular之外,因此$viewValue似乎没有更新。这个怎么样

 elm.bind('blur', function() {
       ctrl.$viewValue = (ctrl.$modelValue / 100).toFixed(2);
       ctrl.$render();
 });
稍有改进: 如果值无效,请不要重新格式化(在我的例子中,无效文本刚刚在模糊中被清除,我认为这对可用性有害)

此外,正如DarkFalcon所说:格式化程序应该向后迭代

最后,不要使用for in迭代数组,至少在没有检查hasOwnProperty()的情况下是这样(对我来说,代码崩溃是因为它将Array.find()作为格式化程序处理)


另一种实现是触发angular的格式化程序。Angular 1.5实现监视$modelValue的更改,然后触发$formatters。要手动执行此操作,可以执行此操作

function triggerFormattersAndRender(ngModel, scope) {
  /* Triggers angulars formatters, which watches for $modelValue changes */
  var originalModelValue = ngModel.$modelValue;
  if (originalModelValue === null) return;

  ngModel.$modelValue = null;
  scope.$digest();
  ngModel.$modelValue = originalModelValue;
  scope.$digest();
}
然后在指令中

function link(scope, elem, attrs, ngModel) {

    elem.bind('blur', function() {
        triggerFormattersAndRender(ngModel, scope);
    });

    // when we get focus, display full precision
    elem.bind('focus', function() {
      if (ngModel.$modelValue) {
        ngModel.$setViewValue(ngModel.$modelValue.toString());
        ngModel.$render();
      }
    })

}

谢谢,我尝试过实现这个,但是$render什么都不做。我已经用一个新的部分更新了这个问题。10.00===10//true。00在电视上没有任何意义javascript@ShadowBelmolve请参阅您答案下的评论。你有过AngularJS的经验吗?restrict:“A”表示你只想让指令像属性一样使用,有4种不同类型的限制,其他的是“E”元素、“C”类和“Co”元素(使用较少-见文档)。您可以有多个restrict:'EAC'About
$formatters
,Angular文档中说“函数以相反的数组顺序调用,每个函数都将值传递给下一个。”该指令以错误的顺序调用它们。我想我会为其他人记下这一点,因为在使用多个格式化程序时,这让我感到有点不舒服。您的解决方案也应该作为答案发布。我只是用它来解决一个类似的问题,所以谢谢你!您还应该明确它是基于这一点的,这不是关于Javascript本身的问题,而是关于AngularJS的问题。你读过/理解代码了吗?模型值存储为整数便士(美分),但表单输入元素处理包含值呈现的字符串,单位为磅(美元),小数点后两位<代码>(modelValue/100)。toFixed(2)
从整数创建字符串。您的答案激发了一个更好的解决方案。请看我问题的结尾,以获得一个通用的解决方案。@chrisdew我很高兴我启发你获得了一个通用的解决方案。我(显然)专注于你的特定应用程序的问题。我要玩它。这可能是angular ui组中使用的一种有趣的技术。我将由我的合作伙伴来管理它。
function triggerFormattersAndRender(ngModel, scope) {
  /* Triggers angulars formatters, which watches for $modelValue changes */
  var originalModelValue = ngModel.$modelValue;
  if (originalModelValue === null) return;

  ngModel.$modelValue = null;
  scope.$digest();
  ngModel.$modelValue = originalModelValue;
  scope.$digest();
}
function link(scope, elem, attrs, ngModel) {

    elem.bind('blur', function() {
        triggerFormattersAndRender(ngModel, scope);
    });

    // when we get focus, display full precision
    elem.bind('focus', function() {
      if (ngModel.$modelValue) {
        ngModel.$setViewValue(ngModel.$modelValue.toString());
        ngModel.$render();
      }
    })

}