Reputation: 1689
I need to make it possible to select a weight in kg and pounds. But my modelValue should always contain the value in kilograms.
So i created the following 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>
And I made a directive weight
with an attribute weigt-representation
. This directive will parse/format the values I have in my 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);
}
});
}
};
});
The problem is that whenever I change radiobuttons, I need to re-format the viewValue
. So I should only rerun the formatters. I red that formatters only get exectued when the modelValue is changed. For that reason I added ngModelController.$modelValue = ngModelController.$modelValue - 1;
. The formatters do get called, but the valueFromModel
does not contain the edited value, but the value before the minus 1.
Tbh, its working perfectly to my needs, but I don't understand why it's working
Also, the modelValue could have any amount of fraction digits, and the viewValue should be fixed to 2 fraction digits
My question: 1. Why is behaviour occuring? 2. Is this the right way to induce the re-run of formatters without changing the actual modelValue, or is this just a dirty hack?
Upvotes: 2
Views: 1037
Reputation: 5353
This is a dirty hack, use $setViewValue to change the viewValue, since you implements the $parsers that will be called when viewValue is changed it'll work fine.
About what you do work : the ngModelController has a watch on his ngModel so it can refresh the view if you change it.
EDIT : add sample code from my last comment which is the one accepted by the author : using a flag to not change ngModel if the last change was just a change of unit :
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
});
Note order of those 3 javascript instructions does not count, i just order it like this to be more readable has an answer.
Upvotes: 2