使用AngularJS在textarea中的插入位置

时间:2014-03-18 11:36:15

标签: angularjs data-binding scope caret

我问自己,我是否正确行事。我遇到的问题是我希望在AngularJS更新textarea值后保留插入位置。

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;
        });

    });
});

假设我开始在textarea中输入一些文字。然后我按下按钮,很快就会添加&#34;期间&#34!;在$scope.editor值的末尾。在5秒超时期间,我再次关注textarea并编写更多文本。 5秒后,我的textarea值会更新。

我正在关注$scope.editor值。 editorListener将在每$digest个周期执行。在这个循环中也会发生双向数据绑定。我需要在数据绑定后纠正插入位置。 $scope.$evalAsync(...)是否应该在哪里进行?

1 个答案:

答案 0 :(得分:0)

这是我用来操纵插入位置的指令;但是,正如我在评论中所说,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将运行并且&#34;将文本附加到结尾&#34;喜欢它应该这样做。请提供更多信息,我会根据需要更新。

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
}]);