Question

I have an instance where I'm replacing the value of ngModel through ngChange. The cursor jumps to the end of the input field after each change (assuming because I'm assigning the result to the same $scope variable.)
I'd like to know how I can prevent this behavior?

  $scope.compute1 = 0;
  $scope.compute2 = 10;

  $scope.math = function() {
    $scope.compute1 = parseInt($scope.compute1);
    $scope.compute2 = parseInt($scope.compute2);

    $scope.compute1 = parseInt($scope.compute1);
  };

fiddle

Example of problem: if a user types in 1000. It's fine. But then if they want to go back and change the number to 156000 by just adding the 5 and 6, the 6 would actually be appended to the end: 15006.

Was it helpful?

Solution

The cursor goes to the end because we modify data by using parseInt.

I suggest you to store the caret position before and then when you're done doing things, set it back.

This example might help you: Link

OTHER TIPS

Two suggestions:

1 Why not just use number input.

<div ng-app='myApp'>
    <div ng-controller="myCtrl">
    <input id="compute1" ng-model="compute.c1" ng-change="math()" type="number"/>
    <input id="compute2" ng-model="compute.c2" ng-change="math()" type="number"/>
  </div>
</div>

2 Two-Way databinding should always be used with the "dot" notation:

$scope.compute = {c1: 0, c2: 10};

$scope.math = function() {
  $scope.compute.c1 = parseInt($scope.compute.c1);
  $scope.compute.c2 = parseInt($scope.compute.c2);
};

and update your html accordingly to have ng-model="compute.c1" etc.

Depending on what math() does, you could make the computation happen on blur instead of change. This way the conversion will only happen when the user tabs (or clicks) out of the input.

See Angularjs: input[text] ngChange fires while the value is changing for an example of this.

Very quick and simple fix to delay the ng-model-options. I had the same issue this worked for me: on your input ->

ng-model-options="{debounce: 750}"

I just wrote this directive which basically allows you to format the text and keep cursor position it's not flawless but works pretty well. Just make sure to return the value in the format function instead of actually changing the value and use it the same as you would the regular ng-change:

.directive('ngChangeFormat', function() {
        return {
            restrict: 'A',
            require: '?ngModel',
            link: function(scope, element, attr, controller) {
                controller.$viewChangeListeners.push(function() {
                    var el = element[0];
                    var start = el.selectionStart;
                    var end = el.selectionEnd;
                    var originalValue = controller.$viewValue;
                    var formattedValue = scope.$eval(attr.ngChangeFormat);
                    controller.$setViewValue(formattedValue);
                    controller.$render();
                    if(start === originalValue.length)
                        el.setSelectionRange(formattedValue.length, formattedValue.length);
                    else
                        el.setSelectionRange(start, end);
                });
            }
        };
    })
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top