带格式化程序和解析器的Angular指令。不知道为什么这样做

时间:2016-03-11 08:04:44

标签: angularjs angularjs-directive angular-directive

我需要选择以kg和磅为单位的重量。但我的modelValue应始终包含以千克为单位的值。

所以我创建了以下HTML。

<div>
   <label>{{'aircraftModal.mtom' | translate}}:</label>
   <label><input type="radio" name="weightRadio" ng-model="AircraftCtrl.weightRepresentation" ng-value="'kg'" >Kilogram</label>
   <label><input type="radio" name="weightRadio" ng-model="AircraftCtrl.weightRepresentation" ng-value="'pound'">Pound</label>
   <input type="number" step="0.01" ng-model="AircraftCtrl.mtom" weight weight-representation="AircraftCtrl.weightRepresentation">
</div>

我制作了一个带有weight属性的指令weigt-representation。该指令将解析/格式化我在视图/控制器中的值。

angular.module('app.directives').directive('weight', function () {
return {
    require: 'ngModel',
    restrict: 'A',
    scope: {
        weightRepresentation: "=weightRepresentation"
    },
    link: function(scope, elem, attrs, ngModelController) {
        var conversionPoundsToKilogram = 0.45359237;

         ngModelController.$formatters.unshift(function(valueFromModel) {
             if(!valueFromModel) return valueFromModel;
             if(scope.weightRepresentation === 'pound'){
                valueFromModel = valueFromModel / conversionPoundsToKilogram;
             }
             return parseFloat(valueFromModel).toFixed(2);
         });

         ngModelController.$parsers.push(function(valueFromInput) {
             if(!valueFromInput) return valueFromInput;
             if(scope.weightRepresentation === 'pound'){
                valueFromInput = valueFromInput * conversionPoundsToKilogram;
             }
             return valueFromInput;
         });

         scope.$watch('weightRepresentation', function(newWeight, oldWeight){
             if(ngModelController.$modelValue){
                 console.log("before " + ngModelController.$modelValue);
                 ngModelController.$modelValue = ngModelController.$modelValue - 1;
                 console.log("After" + ngModelController.$modelValue);
             }
         });
    }
};
});

问题在于每当我改变单选按钮时,我都需要re-format the viewValue。所以我应该只重新运行格式化程序。我更红格式化格式化程序只有在更改modelValue时才会被激活。出于这个原因,我添加了ngModelController.$modelValue = ngModelController.$modelValue - 1;。格式化程序会被调用,但valueFromModel不包含已编辑的值,而是包含减1之前的值。

Tbh,它完全符合我的需求,但我不明白它为什么会起作用

此外,modelValue可以包含任意数量的小数位数,而viewValue应该固定为2位小数

我的问题:  1.为什么会出现这种行为?  2.这是在不改变实际modelValue的情况下引导格式化程序重新运行的正确方法,还是这只是一个肮脏的黑客攻击?

1 个答案:

答案 0 :(得分:2)

这是一个肮脏的黑客,使用$ setViewValue来更改viewValue,因为你实现了在更改viewValue时将被调用的$解析器,它将正常工作。

关于你的工作:ngModelController在他的ngModel上有一个监视器,因此如果你改变它就可以刷新视图。

编辑:从我上一篇评论中添加示例代码,该代码是作者接受的代码:如果最后一次更改只是单位更改,则使用标记不更改ngModel:

var unitChanged = false;

scope.$watch('weightRepresentation', function(newWeight, oldWeight){
         if(ngModelController.$modelValue){
             unitChanged = true;
             // compute new viewValue and update it using $setViewValue
             [...]
         }
     });

ngModelController.$parsers.push(function(valueFromInput) {
         if(!valueFromInput) return valueFromInput;
         if(unitChanged){
               unitChanged = false;
               return ngModelControler.$modelValue;
         }
         [...]// normal code
     });

注意那些3个javascript指令的顺序不计算,我只是命令它这样更具可读性有答案。