I\'m having problems binding a number value using AngularJS.
I\'ve put a simplified example on JSFiddle: http://jsfiddle.net/treerock/ZvdXp/
TypeScript version inspired ainos984, for the sake of posterity
export class ngIntegerDirective implements ng.IDirective {
static directiveKey: string = 'ngInteger';
require: string = 'ngModel';
link = (scope, ele, attr, ctrl: ng.INgModelController) => {
ctrl.$parsers.unshift(function (viewValue) {
let result: number = parseInt(viewValue,10);
if (isNaN(result)) {
result = 0;
}
return result;
});
}
public static Factory(): ng.IDirectiveFactory {
const directive = () => new ngIntegerDirective();
directive.$inject = []; //injecter les dépendances ici
return directive;
}
}
I've expanded on Tim's answer to make it correct the data type after the user updates the control value as well.
myApp.directive('numericbinding', function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
model: '=ngModel',
},
link: function (scope, element, attrs, ngModelCtrl) {
if (scope.model && typeof scope.model == 'string') {
scope.model = parseInt(scope.model);
}
scope.$watch('model', function(val, old) {
if (typeof val == 'string') {
scope.model = parseInt(val);
}
});
}
};
});
If you prefer to save a numeric value in the model, you can use a directive that convert the string generated by the text input and by the range input in a numeric value through the angular parser, like so:
myApp.directive('numericsaving', function () {
return {
restrict: 'A',
require: '?ngModel',
scope: {
model: '=ngModel'
},
link: function (scope, element, attrs, ngModelCtrl) {
if (!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function (value) {
if (!value || value==='' || isNaN(parseInt(value)) || parseInt(value)!==value) {
value=0;
}
return parseInt(value);
});
}
};
});
In the HTML, leave the number input as is and add the directive in the others inputs this way:
<input type="number" min="0" max="50" value="{{value}}" ng-model="value" />
<input type="range" min="0" max="50" value="{{value}}" ng-model="value" numericsaving/>
<input type="text" value="{{value}}" ng-model="value" numericsaving/>
The angular parser will translate the string input in a numeric value before saving it in model, so the numeric input will automatically work. Here the complete fiddle.
Moreover, if the user inserts letters or any strange character in the text input, they will not be saved in the model, preventing invalid value in the single source of truth of your application. Only '+' and '-' character at the begin of the text will be correctly parsed, so even negative value are allowed. I hope this helps! :)
You can also fix this with a directive. I created a directive to force input bound to numeric fields to be numeric.
Html:
myApp.directive('numericbinding', function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
model: '=ngModel',
},
link: function (scope, element, attrs, ngModelCtrl) {
if (scope.model && typeof scope.model == 'string') {
scope.model = parseInt(scope.model);
}
}
};
});
You can add it to your numeric field like this:
<input data-ng-model="stringnumber" numericbinding type="number"/>
full example: http://jsfiddle.net/tdjager/cMYQ3/1/
You're right, it has to do with string vs number types. I used a $scope.watch
statement to fix it: http://jsfiddle.net/ZvdXp/6/