In Angular, bind an attribute from a scope variable * to * ngModel binds input values ​​to `value`

In my Angular app, I defined a custom slider directive that wraps <input type="range">. My custom directive supports ngModelto bind the value of sliders to a variable. A custom directive also requires an attribute fraction-size. It calculates the value and then uses the result to set the value of the stepwrapped one <input>.

I see an error when I combine these two functions - ngModeland the value of the associated attribute. They are executed in the wrong order.

Here is a demo:

angular.module('HelloApp', []);

angular.module('HelloApp').directive('customSlider', function() {
    var tpl = "2 <input type='range' min='2' max='3' step='{{stepSize}}' ng-model='theNum' /> 3";
    
    return {
        restrict: 'E',
        template: tpl,
        require: 'ngModel',
        scope: {
            fractionSize: '='
        },
        link: function(scope, element, attrs, ngModelCtrl) {
            scope.stepSize = 1 / scope.fractionSize;
            
            scope.$watch('theNum', function(newValue, oldValue) {
                ngModelCtrl.$setViewValue(newValue);
            });
            
            ngModelCtrl.$render = function() {
                scope.theNum = ngModelCtrl.$viewValue;
            };
        }
    };
});

angular.module('HelloApp').controller('HelloController', function($scope) {
	$scope.someNumber = 2.5;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>

<div ng-app="HelloApp" ng-controller="HelloController">
    <h3>Custom slider</h3>
    
    <custom-slider ng-model="someNumber" fraction-size="10"></custom-slider>
    
    <h3>View/edit the slider’s value</h3>
    <input ng-model="someNumber"></input>
</div>
Run codeHide result

, 2.5. ( 3). 2.5, , , .

, - , . , , <input> s step undefined 1. ngModel 2.5 - step 1, input 3. , step 0.1 - , .

, step ngModel value?

. . step value , .

,

, step , . , , <input> :

<input type="range" min="2" max="3" step="0.1" ng-model="someNumber">

, value , . customSlider, step .

, ,

  • step ng-model .
  • compile link. stepSize compile, scope .
  • link -. scope.stepSize pre post, -.
  • scope.$digest() scope.stepSize Error: [$rootScope:inprog] $digest already in progress.
  • , , . step s , raw {{}} -. , step - , .
+4
3

@pixelbits ' DOM, ng-model , /

  • , / . DOM.

  • , , Angular (: , , , ). , .

  • 2 ngModelControllers , , , !

  • ngModelController , / .

  • ( / ).

. .

angular.module('HelloApp', []);

angular.module('HelloApp').directive('customSlider', function() {
    var tpl = "2 <input type='range' min='2' max='3' /> 3";
    
    return {
        restrict: 'E',
        template: tpl,
        require: 'ngModel',
        scope: {
            fractionSize: '='
        },
        link: function(scope, element, attrs, ngModelCtrl) {
            var input = element.find('input');          
            input.prop('step', 1 / scope.fractionSize);

            input.on('input', function() {
              scope.$apply(function() {
                ngModelCtrl.$setViewValue(input.prop('value'));
              });
            });

            ngModelCtrl.$render = function(value) {
               input.prop('value', ngModelCtrl.$viewValue);
            };
        }
    };
});

angular.module('HelloApp').controller('HelloController', function($scope) {
    $scope.someNumber = 2.5;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>

<div ng-app="HelloApp" ng-controller="HelloController">
    <h3>Custom slider</h3>
    
    <custom-slider ng-model="someNumber" fraction-size="10"></custom-slider>
    
    <h3>View/edit the slider’s value</h3>
    <input ng-model="someNumber"></input>
</div>
Hide result

http://plnkr.co/edit/pMtmNSy6MVuXV5DbE1HI?p=preview

+2

link DOM, step.

ngModel, theNum: '=ngModel' scope.

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

app.directive('customSlider', function () {
    var tpl = "2 <input type='range' min='2' max='3' ng-model='theNum' /> 3";
    
    return {
        restrict: 'E',
        template: tpl,
        require: 'ngModel',
        scope: {
            fractionSize: '=',
            theNum: '=ngModel'
        },
        link: function (scope, element, attrs, ngModelCtrl) {
            var e = element.find('input')[0];
            
            var step = 1 / scope.fractionSize;
            e.setAttribute('step', step);
            
            scope.$watch('fractionSize', function (newVal) {
                if (newVal) {
                    var step = 1 / newVal;
                    e.setAttribute('step', step);
                }
            });
        }
    };
});

angular.module('HelloApp').controller('HelloController', function($scope) {
    $scope.someNumber = 2.5;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>

<div ng-app="HelloApp" ng-controller="HelloController">
    <h3>Custom slider</h3>
    
    <custom-slider ng-model="someNumber" fraction-size="10"></custom-slider>
    
    <h3>View/edit the slider’s value</h3>
    <input ng-model="someNumber"></input> {{ someNumber }}
</div>
Hide result
+2

, , - .

$timeout(function() {
    $scope.someNumber = 2.5;
});

: , , , () $scope - ajax .

0

Source: https://habr.com/ru/post/1612859/


All Articles