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

我有这个角度代码:

{{element.name}}

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

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

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

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

它们都不起作用 – 有更好的角度方法吗? 在jQuery中使用.closest().find()等函数?

更新:

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

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

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

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

 
{{element.name}}

指示:

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

Plunker

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

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

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

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

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

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

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

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

    这是一个在目标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); } }); }); } }; }); 

    html:

       

    关于Plunker的实例

    我不得不创建一个帐户,只是为了提供简单的答案。

     //Add a bool to your controller's scope that indicates if your element is focused ... //ellipsis used so I don't write the part you should know $scope.userInputActivate = false; ... //Add a new directive to your app stack ... .directive('focusBool', function() { return function(scope, element, attrs) { scope.$watch(attrs.focusBool, function(value) { if (value) $timeout(function() {element.focus();}); }); } }) ...  ... 
    ...
    ... ...

    不使用输入时,请务必重置此变量。 您可以轻松添加ng-blur指令以将其更改回来,或者将其重置为false的其他ng-click事件。 将其设置为false只是为下次准备好了。 这是我发现的ng-blur指令示例,以防您在找到它时遇到问题。

     .directive('ngBlur', ['$parse', function($parse) { return function(scope, element, attr) { var fn = $parse(attr['ngBlur']); element.bind('blur', function(event) { scope.$apply(function() { fn(scope, {$event:event}); }); }); } }]); 

    这是我想出的。 我从Mark Rajcok的解决方案开始,然后开始使其易于重复使用。 它是可配置的,不需要控制器中的任何代码。 焦点是纯粹的表示方面,不应该要求控制器代码

    HTML:

      

    指示:

     chariotApp.directive('passFocusTo', function ($timeout) { return { link: function (scope, element, attrs) { element.bind('click', function () { $timeout(function () { var elem = element.parent(); while(elem[0].id != attrs.focusParent) { elem = elem.parent(); } elem.find("#"+attrs.passFocusTo)[0].focus(); }); }); } }; }); 

    假设:

    • 你的送礼者和接受者就在附近。
    • 当在一个页面上多次使用时,所使用的id是唯一的,或者给予和接受者在DOM的孤立分支中。

    对于使用.closest()方法我建议您应用原型inheritance机制fox扩展角度机会。 像这样:

     angular.element.prototype.closest = (parentClass)-> $this = this closestElement = undefined while $this.parent() if $this.parent().hasClass parentClass closestElement = $this.parent() break $this = $this.parent() closestElement 

    标记:

      

    用法:

      $scope.removeNote = ($event)-> currentNote = angular.element($event.currentTarget).closest("content-list_item") currentNote.remove() 

    要查找输入,请添加Id 并将ngRepeat index作为参数传递给函数ng-click="doSomething(element,$event, $index)"

      
    {{element.name}}

    在函数中使用$timeout和零延迟等待DOM渲染结束。 然后输入可以通过$timeout函数中的getElementById找到。 不要忘记向控制器添加$timeout

     .controller("MyController", function ($scope, $timeout) { $scope.doSomething = function(element,$event, index) { //option A - start manipulating in the dark: $event.srcElement.parentNode.childNodes[1] $timeout(function () { document.getElementById("input" + index).focus(); }); } });