Положение каретки в текстовом поле с AngularJS

Я спрашиваю себя, правильно ли я это делаю. Проблема в том, что я хочу сохранить позицию каретки после того, как AngularJS обновит значение текстовой области.

HTML выглядит так:

<div ng-controlle="editorController">
    <button ng-click="addSomeTextAtTheEnd()">Add some text at the end</button>
    <textarea id="editor" ng-model="editor"></textarea>
</div>

Мой контроллер выглядит так:

app.controller("editorController", function($scope, $timeout, $window) {

    $scope.editor = "";

    $scope.addSomeTextAtTheEnd = function() {
        $timeout(function() {
            $scope.editor = $scope.editor + " Period!";
        }, 5000);
    }

    $scope.$watch("editor", function editorListener() {

        var editor = $window.document.getElementById("editor");
        var start = editor.selectionStart;
        var end = editor.selectionEnd;

        $scope.$evalAsync(function() {
            editor.selectionStart = start;
            editor.selectionEnd = end;
        });

    });
});

Допустим, я начал набирать текст в текстовом поле. Затем я нажимаю кнопку, которая скоро добавит "Период!" в конце $scope.editor значение. В течение 5-секундного перерыва я снова фокусируюсь на текстовой области и пишу еще немного текста. Через 5 секунд мое значение textarea обновляется.

Я слежу за $scope.editor значение. editorListener будет исполняться на каждом $digest цикл. В этом цикле также происходит двусторонняя привязка данных. Мне нужно исправить положение каретки сразу после привязки данных. Является $scope.$evalAsync(...) правильное место, где я должен это делать или нет?

1 ответ

Вот директива, которую я использую для манипулирования положением каретки; однако, как я уже говорил в комментарии, есть проблема с IE.

Ниже приводится кое-что, что может помочь вам спланировать это. В вашем вопросе я заметил одну вещь: вы упомянули условие, при котором пользователь может перефокусировать поле ввода для ввода дополнительного текста, что, как я полагаю, сбрасывает время ожидания; будет ли это условие истинным?

Вместо того, чтобы использовать кнопку для добавления текста, вы бы предпочли просто добавить его без? Как запустить функцию addSomeTextAtTheEnd, когда пользователь не фокусируется из поля ввода?

Если вам нужно использовать кнопку, и пользователь переориентируется на поле ввода и вводит дополнительные данные, вы должны отменить тайм-аут кнопки.

Подобно:

    myVar = setTimeout(function(){ alert("Hello"); }, 3000);

    // Then clear the timeout in your $watch if there is any change to the input.
    clearTimeout(myVar);

Если вы сделаете это таким образом, возможно, вам даже не нужно будет знать положение курсора, поскольку таймаут функции addSomeTextAtTheEnd просто сбрасывается при любом изменении входа до истечения 5-секундного таймаута. Если время ожидания составляет 5 секунд, то addSomeTextAtTheEnd запустится и "добавит текст в конец", как это и должно быть. Пожалуйста, дайте больше информации, и я буду обновлять ее по мере необходимости.

app.directive('filterElement', ['$filter', function($filter){

  return {
    restrict:'A', // Declares an Attributes Directive.
    require: '?ngModel', // ? checks for parent scope if one exists.

    link: function( scope, elem, attrs, ngModel ){
      if( !ngModel ){ return }

      var conditional = attrs.rsFilterElement.conditional ? attrs.rsFilterElement.conditional : null;

      scope.$watch(attrs.ngModel, function(value){
        if( value == undefined || !attrs.rsFilterElement ){ return }

        // Initialize the following values
        // These values are used to set the cursor of the input.
        var initialCursorPosition = elem[0].selectionStart
        var initialValueLength = elem[0].value.length
        var difference = false

        // Sets ngModelView and ngViewValue
        ngModel.$setViewValue($filter( attrs.rsFilterElement )( value, conditional ));
        attrs.$$element[0].value = $filter( attrs.rsFilterElement )( value, conditional );

        if(elem[0].value.length > initialValueLength){ difference = true }
        if(elem[0].value.length < initialValueLength){ initialCursorPosition = initialCursorPosition - 1 }
        elem[0].selectionStart = difference ? elem[0].selectionStart : initialCursorPosition
        elem[0].selectionEnd = difference ? elem[0].selectionEnd : initialCursorPosition
      });
    } // end link
  } // end return
}]);
Другие вопросы по тегам