Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set Caret position in Input with AngularJS

I need to change the caret position of an input, where a given number of digits is added (Example).

app.controller('MainCtrl', function($scope, $element, $timeout, $filter) {
  //$scope.val = '12';
  $scope.$watch('val', function(newValue, oldValue) {
    if (!isNaN(newValue)) {
      if (newValue.length > 3) {
        //Set Caret Position  
      }
    }
  });
});

Is it possible to do something like this example?

I need for example :

Input: 1234.

so the caret position will be 2.

New digit: 9

final: 12934

Thanks in advance.

like image 269
JohnPortella Avatar asked Mar 22 '14 06:03

JohnPortella


3 Answers

I think that such kind of things look better in directives. For example:

app.directive('caret', function() {

    function setCaretPosition(elem, caretPos) {
        if (elem !== null) {
            if (elem.createTextRange) {
                var range = elem.createTextRange();
                range.move('character', caretPos);
                range.select();
            } else {
                if (elem.setSelectionRange) {
                    elem.focus();
                    elem.setSelectionRange(caretPos, caretPos);
                } else
                    elem.focus();
            }
        }
    }

    return {
        scope: {value: '=ngModel'},
        link: function(scope, element, attrs) {
            var caret = Number(attrs.caret);
            scope.$watch('value', function(newValue, oldValue) {
                if (newValue && newValue != oldValue && !isNaN(newValue) && newValue.length > (caret + 1)) {
                    setCaretPosition(element[0], caret);
                }
            });
        }
    };
});

Usage:

<input ng-model='val' caret="2" />

I used setCaretPosition function for cross browser cursor positioning from this answer.

Demo: http://plnkr.co/edit/5RSgzvyd8YOTaXPsYr8A?p=preview

like image 105
dfsq Avatar answered Nov 20 '22 18:11

dfsq


I think that the best approach for this is to make a reusable directive as we are dealing with DOM manipulation.

Link to the demo: http://plnkr.co/edit/qlGi64VO1AOrNpxoKA68?p=preview

var app = angular.module('angularjs-starter', []);

app.controller('MainCtrl', function($scope, $element, $timeout, $filter) {
  $scope.$watch('val', function(newValue, oldValue) {
    if (!isNaN(newValue)) {
      if (newValue.length > 3) {
      // $element.find('input')[0].selectionEnd  = 2;
      }
    }
  });
});

app.directive('setCaret', function() {

  return {
    restrict: 'A',
    link: function(scope,element,attrs) {
      var changed = false;
      element.bind('keypress', function() {
        if(element[0].selectionStart > 3 && !changed) {
          changed = true;
          element[0].selectionEnd = parseInt(attrs.position, 10);
        }
      })

    },
  }

})

You can see in the commented out part in the controller we can have access to this by using $element, but as this is DOM and controllers are not for DOM manipulation we need to make this into a directive.

like image 40
Sten Muchow Avatar answered Nov 20 '22 17:11

Sten Muchow


I also had the same problem.

I thought to solve it creating an appropriate directive. You can find it here. Enjoy it!

Usage

Include directive, declare it by caret-aware attribute

<script src="https://cdn.rawgit.com/leodido/ng-caret-aware/master/caretaware.min.js"></script>
<script type="text/javascript">
  var app = angular.module('myModule', ['leodido.caretAware']);
</script>
...
<div data-ng-app="app">
    <input type="text" name="myname" caret-aware="cursor"/>
</div>

Then on the scope you'll have a variable cursor containing the position of the caret in the input named myname.

Nevertheless, this directive's controller exposes an API

  • getPosition
  • setPosition

For other usage examples see example directory of the above linked github repository.

like image 1
leodido Avatar answered Nov 20 '22 17:11

leodido