在AngularJS中轻松控制dom – 单击按钮,然后将焦点设置为输入元素
我有这个角度代码:
我想要发生的事情:当用户点击按钮时 – 输入元素将被聚焦。
单击按钮元素并将其聚焦后,如何找到输入元素?
我可以做一个看起来像这样的函数:
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
指令并在按钮上使用它:
指示:
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
由于jqLite在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)"
在函数中使用$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(); }); } });