javascript - 如何通过添加/删除 Angular 输入来管理焦点/光标位置?

标签 javascript angularjs angularjs-directive

我正在制定一个指令,当所有输入字段都被填充时,该指令应该自动创建另一个输入字段。因此,在这个示例中,当我停止输入第三个输入时,将出现第四个输入,但我的光标应保留在第三个输入中。

问题是在我的代码中,最终输入始终存在,因此当我更新数据并将其值移动到倒数第二个输入时,它保留焦点,并且我无法聚焦倒数第二个输入当用户在去抖间隔结束后快速开始打字时,速度足够快,可以防止闪烁和字符丢失。

如何才能使其正常工作?

这个问题的 XY 版本是:在 ng-repeat 向 DOM 添加新元素后如何同步执行操作?

ui example

plunk

scope: {
    // String[]
    items: '=',

    // 'input' or 'textarea'
    type: '@',

    // 'text', 'email', 'url', etc.
    inputType: '@'
},

link: function (scope, element) {
    scope._inputType = scope.inputType || 'text';
    scope.temp = {
        item: ""
    };

    var $el = jQuery(element.get(0));

    // add another input when the user stops typing in the last input
    scope.$watch('temp.item', (debounce)(function(){
        if (scope.temp.item) {
            scope.items.push(scope.temp.item);
            scope.temp.item = "";
            var elLast = $el.find('.item-last');
            elLast.blur();

            var currentInput = elLast.prev('.item-input').find('input').get(0);
            var tries = 100;

            // use nextTick to reduce time-to-update
            // this often fires a few times before angular actually updates anything
            nextTick(function again(){
                var target = elLast.prev('.item-input').find('input');

                // has angular updated?  if not: retry
                if (target.get(0) === currentInput && (--tries) > 0) {
                    return nextTick(again);
                }

                // focus and move cursor to end
                target.focus();
                var len = target.val().length;
                target.get(0).setSelectionRange(len, len);
            }, 0, false);
        }
    }, 500));

    // remove empty items after a few seconds
    scope.$watch('items', debounce(function(){
        var items = scope.items;
        var inputs = $el.find('.item-input > *');
        var emptyBeforeFocused = 0;
        var focusedIndex = null;

        for (var i=0; i<inputs.length-1; i++) {
            if (inputs.eq(i).is(':focus')) {
                focusedIndex = i;
                break;
            }
            if(!items[i]) {
                emptyBeforeFocused++;
            }
        }

        var originalLength = scope.items.length;
        scope.items = scope.items.filter(x => x.length);

        // we need to fix focus if a previous element was removed
        if (scope.items.length !== originalLength && emptyBeforeFocused > 0 && focusedIndex) {
            scope.$evalAsync(function(){
                // grab the index of the focused input, minus the preceding removed inputs
                // i.e. the input's new index
                var target = $el.find('.item-input > *').eq(focusedIndex - emptyBeforeFocused);

                // focus and move cursor to end
                target.focus();
                var val = scope.type === 'textarea' ? target.text() : target.val();
                var len = val.length;
                target.get(0).setSelectionRange(len, len);
            }, 0, false);
        }
    }, 5000));
}
<div>
    <div ng-if="type === 'input'">
        <div class="item-input item-type-input" ng-repeat="item in items track by $index">
            <input type="text" ng-model="items[$index]" class="form-control" />
        </div>

        <div class="item-input item-type-input item-last">
            <input type="text" ng-model="temp.item" class="form-control" />
        </div>
    </div>
    <div ng-if="type === 'textarea'">
        <div class="item-input item-type-textarea" ng-repeat="item in items track by $index">
            <textarea ng-model="items[$index]" class="form-control" ></textarea>
        </div>
        <div class="item-input item-type-textarea item-last">
            <textarea ng-model="temp.item" class="form-control" ></textarea>
        </div>
    </div>
</div>

最佳答案

plnkr

.directive('resetFocus', [function(){
  return function(scope, element, attr, ctrl) {
    if(scope.$last){
      element.find('input').focus();
    }
  };
}])

<div class="item-input item-type-input" ng-repeat="item in items track by $index" reset-focus>
    <input type="text" ng-model="items[$index]" class="form-control" />
</div>

由于您也在进行删除,因此您可能需要 $watch('$last')

.directive('resetFocus', [function(){
  return function(scope, element, attr, ctrl) {
    if(scope.$last){
      element.find('input').focus();
    }
    scope.$watch('$last', function(){
        if(scope.$last){
            element.find('input').focus();
        }
    });
  };
}])

该指令在创建时将焦点设置在 ng-repeat 中的最后一个输入元素上。它利用了 ng-repeat 会将 $last 添加到作用域这一事实。

关于javascript - 如何通过添加/删除 Angular 输入来管理焦点/光标位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27884063/

相关文章:

javascript - document.execCommand 在 angularJS 中不起作用

javascript - 我的 $asyncValidator 不工作 - Angular Javascript

javascript - 使用 $http 的 AngularJS 自定义表单验证

javascript - 一段时间后删除嵌套对象 - MongoDB + Node.js

javascript - 选中复选框,自动更新复选框

javascript - 使用选择输入对表进行排序

angularjs - 加载相对templateUrl

javascript - 如何使用 javascript 单击最后一个子链接

Javascript 在 HTML5 DOM 上从数组渲染动画。首先慢跑!第二次运行顺利。怎么会?

javascript - 如何将 AngularJS 模板转换为字符串?