Check out this fiddle: http://jsfiddle.net/bwjbz/6/
I'm trying to strictly enforce positive whole numbers. I have tried several avenues, and I can't seem to get what I'm looking for. (If you try a couple of times you can end up getting a non-number or negative number to stick in the input).
In addition to the above fiddle, I have also tried using the number filter and also tried creating my own directive.
Number filter:
<input type="number" min="0" max="1000" value="{{itm.qty | number:0}}" required data-ng-model="itm.qty" data-ng-change="setQty()" data-whole-number>
You'll notice the data-whole-number directive. I'm not fully comfortable with directives yet, but this is it:
app.directive('wholeNumber', function() {
return function(scope, elem, attrs) {
elem.on("blur", function() {
var num;
num = parseInt(elem.val(), 10);
num = Math.abs(num);
scope.$apply(elem.val(num));
});
};
});
The directive itself does the correct DOM manipulation, but the model doesn't update with the new value.
So there are two aspects to this questions:
The fiddle works to set the correct value on the model, but the model text doesn't update. However, in another method, I set the qty of the model itm to 1 and it changes both the model and the visible value. You'll notice it does in fact change the model correctly (notice the bindings, number of footballs = 1, when value is set to 1.56, for example).
Why isn't the directive propagating the changes to the model?
Thanks so much in advance, -Brian
Update: Working fiddle using a directive: http://jsfiddle.net/mrajcok/U7Je2/
Salient points:
<input type="number" min="0" max="{{maxValue}}" data-ng-model="itm.qty" whole-number>
link: function(scope, elem, attrs) {
elem.on("blur", function() {
var num = Math.abs(parseInt(elem.val(), 10));
num = num > scope.maxValue ? 0 : num;
scope.itm.qty = num
scope.$apply();
// or, the above two lines can be rewritten as
scope.$apply(scope.itm.qty = num);
// or, the blur function can be rewritten as
elem.on("blur", function() {
scope.$apply(function() {
var num = Math.abs(parseInt(elem.val(), 10));
num = num > scope.maxValue ? 0 : num;
scope.itm.qty = num;
});
});
Original "answer":
Regarding your first fiddle, a similar issue came up on SO recently, see AngularJS - reset of $scope.value doesn't change value in template (random behavior)
If we apply the $timeout solution from that post to your issue, wrap the setQty() logic in a $timeout function, and it will work, sort of. See this fiddle. I say "sort of" because a "number" like "2-2-3-4" can be entered, as can "abc". Those bogus values do clear when you change focus. It seems like Angular is not calling setQty() for these bogus entries... I don't know why.
Mark,
The problem with your solution is that the directive needs to know the name of the bound variable. A more useful solution is to update it anonymously (and call any events associated) so that the directive can be used on any partial html bound to any controller:
// update the bound scope variable and if exists call the change function
var evalStr = attrs.ngModel + '=' + num.toString();
if (typeof attrs.ngChange != 'undefined')
{
evalStr += ';'+attrs.ngChange;
}
scope.$apply(evalStr);
Note that the advantage of evaluating 'evalStr' as an argument of scope.$apply means that AngularJS reports any exceptions to the console and the application can continue.