在AngularJS中轻松控制dom - 单击按钮,然后将焦点设置为输入元素

Alo*_*lon 19 javascript jquery angularjs

我有这个角度代码:

<div class="element-wrapper" ng-repeat="element in elements">
  <div class="first-wrapper">
     <div class="button" ng-click="doSomething(element,$event)">{{element.name}}</div>   
  </div>
  <div class="second-wrapper">
    <input type="text" value="{{element.value}}">    
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

我想要发生的事情:当用户点击按钮时 - 输入元素将被聚焦.

单击按钮元素并将其聚焦后,如何找到输入元素?

我可以做一个看起来像这样的函数:

function doSomething(element,$event) {
  //option A - start manipulating in the dark:
  $event.srcElement.parentNode.childNodes[1]

  //option B - wrapping it with jQuery:
   $($event.srcElement).closest('.element-wrapper').find('input').focus();
}
Run Code Online (Sandbox Code Playgroud)

它们都不起作用 - 是否有更好的角度方法可以做到这一点?使用功能,如.closest().find()在jQuery的?

更新:

我发现这个黑客工作(但它似乎仍然不是正确的解决方案):

function doSomething(element,$event) {
   setTimeout(function(){
     $($event.srcElement).closest('.element-wrapper').find('input').focus();
   },0)
}
Run Code Online (Sandbox Code Playgroud)

我用setTimeout包装它,所以在Angular完成它的所有操作后,它会聚焦在input元素上.

Mar*_*cok 38

DOM操作应该在指令中而不是控制器中.我会定义一个focusInput指令并在按钮上使用它:

<div class="button" focus-input>{{element.name}}</div>   
Run Code Online (Sandbox Code Playgroud)

指示:

app.directive('focusInput', function($timeout) {
  return {
    link: function(scope, element, attrs) {
      element.bind('click', function() {
        $timeout(function() {
          element.parent().parent().find('input')[0].focus();
        });
      });
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

Plunker

由于jqLit​​e在DOM遍历方法方面相当有限,我不得不使用parent().parent().您可能希望使用jQuery或一些JavaScript方法.

正如您已经发现的那样,$timeout需要focus()在浏览器呈现后调用该方法(即完成处理click事件).

find('input')[0]让我们访问DOM元素,允许我们使用JavaScript focus()方法(而不是find('input').focus()需要jQuery).

  • @Freewind,任何类型的DOM活动(遍历,焦点(),添加/删除元素或类)都应该在指令中完成.当然,你可以将一行jQuery放入一个控制器中来执行此操作,但是你违反了"关注点的清晰分离".这一切都取决于您希望架构的清洁程度.关于"一次使用",你可以通过传入一个id或classname或其他东西作为属性来使这个指令更通用/可重用,然后指令就可以找到它. (8认同)
  • 现在,我喜欢角度,并将它用于一些非常复杂的应用程序.这种类型的单指令非常简单的dom操作只是英国媒体报道.整个事情是一行更易读的vanilla js或jQuery,如果这是你的想象. (3认同)

Sly*_*nal 10

我最近一直在看AngularJS,并遇到了类似的情况.

我正在努力从主角度页面更新Todo示例应用程序,以便在双击待办事项时添加"编辑"模式.

我能够使用基于模型/状态的方法解决我的问题.如果您的应用程序以类似的方式工作(您希望在模型上的某些条件为真时将焦点设置在字段上),那么这也可能适用于您.

我的方法是将model.editing属性设置为true当用户双击todo标签时 - 显示可编辑输入并隐藏常规不可编辑标签和复选框.我们还有一个调用的自定义指令focusInput,它在同一个model.editing属性上有一个监视,并在值更改时将焦点设置在文本字段上:

<li ng-repeat="todo in todos">

    <div>
        <!-- Regular display view. -->
        <div ng-show="todo.editing == false">
            <label class="done-{{todo.done}}" ng-dblclick="model.editing = true">
                <input type="checkbox" ng-model="todo.done"/>{{todo.text}}
            </label>
        </div>

        <!-- Editable view. -->
        <div ng-show="todo.editing == true">
            <!--
                - Add the `focus-input` directive with the statement "todo.editing == true".
                  This is the element that will receive focus when the statement evaluates to true.

                - We also add the `todoBlur` directive so we can cancel editing when the text field loses focus.
            -->
            <input type="text" ng-model="todo.text" focus-input="todo.editing == true" todo-blur="todo.editing = false"/>
        </div>
    </div>

</li>
Run Code Online (Sandbox Code Playgroud)

这是一个focusInput指令,当某些条件的计算结果为true:时,它会将焦点设置在当前元素上:

angular.module('TodoModule', [])
    // Define a new directive called `focusInput`.
    .directive('focusInput', function($timeout){
        return function(scope, element, attr){

            // Add a watch on the `focus-input` attribute.
            // Whenever the `focus-input` statement changes this callback function will be executed.
            scope.$watch(attr.focusInput, function(value){
                // If the `focus-input` statement evaluates to `true`
                // then use jQuery to set focus on the element.
                if (value){
                    $timeout(function(){
                        element.select();
                    });
                }
            });

        };
    })
    // Here is the directive to raise the 'blur' event.
    .directive('todoBlur', [
        '$parse', function($parse){
            return function(scope, element, attr){

                var fn = $parse(attr['todoBlur']);
                return element.on('blur', function(event){

                    return scope.$apply(function(){
                        return fn(scope, {
                            $event: event
                        });
                    });

                });

            };
        }
    ]);
Run Code Online (Sandbox Code Playgroud)


Ome*_*hem 5

这是一个在目标dom元素上触发焦点事件的指令:

AngularJs指令:

app.directive('triggerFocusOn', function($timeout) {
    return {
        link: function(scope, element, attrs) {
            element.bind('click', function() {
                $timeout(function() {
                    var otherElement = document.querySelector('#' + attrs.triggerFocusOn);

                    if (otherElement) {
                        otherElement.focus();
                    }
                    else {
                        console.log("Can't find element: " + attrs.triggerFocusOn);
                    }
                });
            });
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

html:

<button trigger-focus-on="targetInput">Click here to focus on the other element</button>
<input type="text" id="targetInput">
Run Code Online (Sandbox Code Playgroud)

关于Plunker的实例