Question

The directive I have created uses the function setFormatting to mask the text value in an input field.

scope.$watch(element, function() {
    modelCtrl.$setViewValue(setFormatting(element.val(), attrs.symbol));
    modelCtrl.$render();
});

element.bind('blur', function() {
    modelCtrl.$setViewValue(setFormatting(element.val(), attrs.symbol));
    modelCtrl.$render();
});

The scope.$watch applies the mask when the content is loaded/applied the first time, the element.bind applies the mask for the other times. The scope.$watch is storing the symbol (if there is one) as part of the ng-model variable. The element.bind is not. I thought $setViewValue() and $render() did not update the ng-model variable. Where is the variable being updated?

See attached fiddle: http://jsfiddle.net/PJ3M4/
Thanks.

Was it helpful?

Solution 4

I was able to get the ng-model to store values the way I wanted to by adding a modelCtrl.$parsers.push() { ... } to my scope.$watch() { ... }.

scope.$watch(element, function() {
    modelCtrl.$parsers.push(function(inputValue) {
        showAlert("Watch", 1);

        if (!prev) {
            prev = false;
            var returnVal = checkVal(inputValue, modelCtrl, decimals, true, minVal, maxVal);

            if (String(returnVal) === ".") {
                setAndRender(modelCtrl, "");
                return "";
            }
            else {
                return returnVal;
            }
        }
        return String(inputValue).replace(/[^0-9 . -]/g, '');
    });

    prev = true;
    setAndRender(modelCtrl, setFormatting(element.val(), decimals, attrs.prefix, attrs.symbol));
});

OTHER TIPS

Here we used $formatters.unshift and $filter:

enter image description here

JS

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

fessmodule.controller('fessCntrl', function ($scope) {
    $scope.test = 123456879;
});
fessmodule.$inject = ['$scope'];

fessmodule.directive('format', ['$filter', function ($filter) {
    return {
        require: '?ngModel',
        link: function (scope, elem, attrs, ctrl) {
            if (!ctrl) return;

            var symbol = "°"; // dummy usage

            ctrl.$formatters.unshift(function (a) {
                return $filter(attrs.format)(ctrl.$modelValue) +  symbol;
            });

            ctrl.$parsers.unshift(function (viewValue) {
                var plainNumber = viewValue.replace(/[^\d|\-+|\.+]/g, '');
                elem.val($filter('number')(plainNumber) + symbol);
                return plainNumber;
            });
        }
    };
}]);

HTML

 <input type="text" ng-model="test" format="number"/>

Demo Fiddle

As a side note

You can find this helpful too: Fiddle

The $watch is executed inside a 'digest' loop. The element.bind callback is called from outside angular, so you must add an explicit call to scope.$apply():

element.bind('blur', function() {
    modelCtrl.$setViewValue(setFormatting(element.val(), attrs.symbol));
    modelCtrl.$render();
    scope.$apply();
});

Updated fiddle

See the docs for info about AngularJS's event loop.

You can also use simply

ui-mask="{{'999,999,999°'}}"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top