Reputation: 24411
My form data is returned from a REST call. Example data is:
{
id: 4
version: 3
code: "ADSFASDF"
definition: "asdflkj"
value: "1234"
active: "false"
formula: false
validTo: "2014-12-31T05:00:00"
validFrom: "2010-12-31T10:00:00"
}
I'm running into trouble using input[number]
and input[date]
fields as they require the data to be a number or a date respectively and not a string. Similar problems occur for booleans (check boxes), etc.
I thought I could get around it using a $formattter
, but the value passed to the formatter is always "". I presume this means the that $formatter
is called after Angular has already tried to parse the data model.
Without having to initially cast everything in my controller, is there a way to cast the data via a directive, or within the HTML tag directly?
Ex:
<input type="number" class="form-control" ng-model="charge.value" jk-numeric id="chargeValue"/>
$formatter:
app.directive( 'jkNumeric',
function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
var stringToNum = function(text) {
if( angular.isNumber(text) )
return text;
else
return parseInt( text, 10);
}
// assign the parser and the formatter to the model
ngModelCtrl.$formatters.unshift(stringToNum);
}
};
});
Upvotes: 0
Views: 1492
Reputation: 123739
You can do this way :-
Set your directive to a higher priority so that the directive runs before ng-model
does its viewValue
/modelValue
evaluation, and do a 2 way binding with ngModel
to get the actual value you set (and not the viewValue of ngModel), and to support async data assignment keep a temporary watch. You cannot possibly do it with formatters
because they run after ngModel
has evaluated the value.
.directive( 'jkNumeric',
function() {
return {
restrict: 'A',
require: 'ngModel',
priority:999999, //<-- Give a higher priority
scope: {
model:'=ngModel' //<-- A 2 way binding to read actual bound value not the ngModel view value
},
link: function(scope, element, attrs, ngModelCtrl) {
//Perform whatever formatting you want to do.
function stringToNum(text) {
return +text;
}
var unwatch = scope.$watch('model', function(val){
if(!val) return;
ngModelCtrl.$setViewValue(stringToNum(val));
ngModelCtrl.$render();
unwatch();
});
}
};
});
Another way to watch would be to watch on evaluated value of ngModel attribute.
require: 'ngModel',
priority:999999,
link: function(scope, element, attrs, ngModelCtrl) {
function formatToNumber(text) {
//do something and return numeric value
}
scope.$watch(function(){
return scope.$eval(attrs.ngModel); //evaluate the scope value
}, function(val){
if(!val) return;
ngModelCtrl.$setViewValue(formatToNumber(val));
ngModelCtrl.$render();
});
Upvotes: 2
Reputation: 3172
Could you try something like:
app.directive( 'jkNumeric',
function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
if (angular.isString(ngModelCtrl.$viewValue) {
ngModelCtrl.$setViewValue(parseInt(ngModelCtrl.$viewValue, 10));
ngModelCtrl.$render();
}
}
};
});
Upvotes: 1