17

I'm just starting to play around with AngularJS and trying to understand the binding technique. For starters, I tried to make a simple conversion calculator (dozens to pieces, pieces to dozens). That worked well, but when I tried to bind both a range input and a number input to the same model property the number input does not update when the range value is adjusted. I have a jsfiddle showing the behavior:

common javascript for broken and working fiddles:

var myApp = angular.module('myApp', []);

myApp.controller('CalcCtrl', function ($scope) {
    var num = 0.0;
    $scope.qty = new Quantity(12);
    $scope.num = num;
});

function Quantity(numOfPcs) {
    var qty = numOfPcs;
    var dozens = numOfPcs / 12;

    this.__defineGetter__("qty", function () {
        return qty;
    });

    this.__defineSetter__("qty", function (val) {
        qty = val;
        dozens = val / 12;
    });

    this.__defineGetter__("dozens", function () {
        return dozens;
    });

    this.__defineSetter__("dozens", function (val) {
        dozens = val;
        qty = val * 12;
    });
}

BROKEN FIDDLE

html:

<div ng-controller="CalcCtrl">
    <form>
        <label for="pcs">Pieces:</label>
        <input type="number" min="0" ng-model="qty.qty" size="20" id="pcs"
        />
        <input type="range" min="0" max="100" ng-model="qty.qty" />
        <br/>
        <label for="numOfDozens">Dozens</label>
        <input type="number" min="0" ng-model="qty.dozens" size="20"
        id="numOfDozens" />
    </form>
</div>

However, binding two number inputs to the same model property seems to work fine as shown in this fiddle:

WORKING FIDDLE

html:

<div ng-controller="CalcCtrl">
    <form>
        <label for="pcs">Pieces:</label>
        <input type="number" min="0" ng-model="qty.qty" size="20" id="pcs"
        />
        <input type="number" min="0" max="100" ng-model="qty.qty" />
        <br/>
        <label for="numOfDozens">Dozens</label>
        <input type="number" min="0" ng-model="qty.dozens" size="20"
        id="numOfDozens" />
    </form>
</div>

Any ideas how to get a range and number input bound to a single model property in AngularJS? Thanks.

1

3 Answers 3

17

The problem here is that the input type="range" works with Strings and not with Numbers (while input type="number" only works with Numbers).

http://www.w3.org/wiki/HTML/Elements/input/range

The range state represents a control for setting the element's value to a string representing a number.

If you add val = parseInt(val) as your first instruction on the qty setter it should work:

this.__defineSetter__("qty", function (val) {        
    val = parseInt(val);
    qty = val;
    dozens = val / 12;
});

jsfiddle: http://jsfiddle.net/bmleite/2Pk3M/2/

Sign up to request clarification or add additional context in comments.

4 Comments

Isn't a range input basically a number select? Why are they using strings?
It should be parseInt(val, 10);
@LiviuT. They probably used a string to be backwards-compatible. On older browsers that don’t implement type="range", the input will still be usable as a text field, with a string-type value. Making value still be a string on newer browsers avoids browser compatibility bugs.
It should be Number(val);
7

I think this solution is more generic.

myApp.directive('input', function() {
return {
    restrict: 'E',
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
        if ('type' in attrs && attrs.type.toLowerCase() === 'range') {
            ngModel.$parsers.push(parseFloat);
        }
    }
};

});

full explanation

1 Comment

I like this solution. Although I replaced parseFloat with Number ;-)
0

You can solve it using ng-model-options. I changed jsfiddle and here is the code:

html:

<div ng-controller="CalcCtrl">
    <form>
        <label for="pcs">Pieces:</label>
        <input type="number" min="0" ng-model="qty.qty" size="20" id="pcs" ng-model-options="{ getterSetter: true }"/>
        <input type="range" min="0" max="100" ng-model="qty.qty" ng-model-options="{ getterSetter: true }"/>
        <br/>
        <label for="numOfDozens">Dozens</label>
        <input type="number" min="0" ng-model="qty.dozens" size="20"
        id="numOfDozens" ng-model-options="{ getterSetter: true }"/>
    </form>
</div>

js:

var myApp = angular.module('myApp', []);

myApp.controller('CalcCtrl', function ($scope) {
    var num = 1.0;
    $scope.qty = {
    qty:function (val) {
        return arguments.length ? (num = parseFloat(val)) : num;
     }, 
     dozens: function (val) {
            return arguments.length ? (num = val*12) : num/12;
        }
     };
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.