Angular 带有格式化程序和解析器的指令。不确定为什么会这样
Angular directive with formatters and parsers. Not sure why this is working
我需要 select 以公斤和磅为单位的重量。但是我的 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>
然后我创建了一个带有属性 weigt-representation
的指令 weight
。该指令将 parse/format 我在 view/controller.
中的值
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 之前的值。
老天,它完全符合我的需要,但我不明白为什么它会起作用
此外,modelValue 可以有任意数量的小数位,viewValue 应该固定为 2 个小数位
我的问题:
1. 为什么行为会发生?
2. 这是在不改变实际 modelValue 的情况下重新 运行 格式化程序的正确方法,还是这只是一个肮脏的 hack?
这是一个肮脏的 hack,使用 $setViewValue 来更改 viewValue,因为您实现了 $parsers,当 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 指令的顺序不算数,我只是这样排序以提高可读性。
我需要 select 以公斤和磅为单位的重量。但是我的 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>
然后我创建了一个带有属性 weigt-representation
的指令 weight
。该指令将 parse/format 我在 view/controller.
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 之前的值。
老天,它完全符合我的需要,但我不明白为什么它会起作用
此外,modelValue 可以有任意数量的小数位,viewValue 应该固定为 2 个小数位
我的问题: 1. 为什么行为会发生? 2. 这是在不改变实际 modelValue 的情况下重新 运行 格式化程序的正确方法,还是这只是一个肮脏的 hack?
这是一个肮脏的 hack,使用 $setViewValue 来更改 viewValue,因为您实现了 $parsers,当 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 指令的顺序不算数,我只是这样排序以提高可读性。