在AngularJS中,“Angular的方法”是什么?
更具体的要求:
当打开一个模态时,将焦点设置在这个模态内预定义的<input>上。 每次<input>变得可见时(例如,通过单击某个按钮),将焦点设置在它上。
我尝试用自动对焦来实现第一个要求,但这只在Modal第一次打开时有效,并且只在某些浏览器中有效(例如在Firefox中它不起作用)。
在AngularJS中,“Angular的方法”是什么?
更具体的要求:
当打开一个模态时,将焦点设置在这个模态内预定义的<input>上。 每次<input>变得可见时(例如,通过单击某个按钮),将焦点设置在它上。
我尝试用自动对焦来实现第一个要求,但这只在Modal第一次打开时有效,并且只在某些浏览器中有效(例如在Firefox中它不起作用)。
当前回答
这是我最初的解决方案:
砰砰作响
var app = angular.module('plunker', []);
app.directive('autoFocus', function($timeout) {
return {
link: function (scope, element, attrs) {
attrs.$observe("autoFocus", function(newValue){
if (newValue === "true")
$timeout(function(){element[0].focus()});
});
}
};
});
而HTML:
<button ng-click="isVisible = !isVisible">Toggle input</button>
<input ng-show="isVisible" auto-focus="{{ isVisible }}" value="auto-focus on" />
它的作用:
使用ng-show,当输入变得可见时,它会聚焦输入。没用$watch和$on。
其他回答
我不认为$timeout是一个将元素集中在创建上的好方法。下面是一个使用内置angular功能的方法,它是从angular文档的黑暗深处挖掘出来的。注意“link”属性是如何被分为“pre”和“post”的,分别是pre-link和post-link函数。
工作示例:http://plnkr.co/edit/Fj59GB
// this is the directive you add to any element you want to highlight after creation
Guest.directive('autoFocus', function() {
return {
link: {
pre: function preLink(scope, element, attr) {
console.debug('prelink called');
// this fails since the element hasn't rendered
//element[0].focus();
},
post: function postLink(scope, element, attr) {
console.debug('postlink called');
// this succeeds since the element has been rendered
element[0].focus();
}
}
}
});
<input value="hello" />
<!-- this input automatically gets focus on creation -->
<input value="world" auto-focus />
完整的AngularJS指令文档:https://docs.angularjs.org/api/ng/service/$compile
这里只是一个新手,但我能够让它在ui.bootstrap.modal中工作,使用这个指令:
directives.directive('focus', function($timeout) {
return {
link : function(scope, element) {
scope.$watch('idToFocus', function(value) {
if (value === element[0].id) {
$timeout(function() {
element[0].focus();
});
}
});
}
};
});
在$modal中。我使用下面的方法来指示焦点应该放在哪里的元素:
var d = $modal.open({
controller : function($scope, $modalInstance) {
...
$scope.idToFocus = "cancelaAteste";
}
...
});
在模板上我有这个:
<input id="myInputId" focus />
我发现其他一些答案过于复杂,而你真正需要的只是这个
app.directive('autoFocus', function($timeout) {
return {
restrict: 'AC',
link: function(_scope, _element) {
$timeout(function(){
_element[0].focus();
}, 0);
}
};
});
使用
<input name="theInput" auto-focus>
我们使用超时来让dom中的东西呈现,即使它是零,它至少会等待它-这种方式也适用于模态和其他东西
我想在寻找一个更好的解决方案,但没有找到它,而是不得不创造它之后,为这个讨论做出贡献。
标准: 1. 解决方案应该独立于父控制器范围,以增加可重用性。 2. 避免使用$watch来监视某些条件,这既缓慢,又增加了摘要循环的大小,并且使测试更加困难。 3.避免$timeout或$scope.$apply()触发摘要循环。 4. input元素出现在使用Directive打开的元素中。
这是我最喜欢的解决方案:
指令:
.directive('focusInput', [ function () {
return {
scope: {},
restrict: 'A',
compile: function(elem, attr) {
elem.bind('click', function() {
elem.find('input').focus();
});
}
};
}]);
Html:
<div focus-input>
<input/>
</div>
我希望这篇文章能帮助到一些人!
##(编辑:我已经在这个解释下面添加了一个更新的解决方案)
马克·拉杰科克是…他的答案是一个有效的答案,但它有一个缺陷(对不起,马克)…
…尝试使用布尔值来聚焦输入,然后模糊输入,然后尝试再次使用它来聚焦输入。它不会工作,除非你重置布尔值为假,然后$digest,然后重置为真。即使在表达式中使用字符串比较,也必须将字符串更改为其他内容$digest,然后再更改回来。(这个问题已经通过模糊事件处理程序解决了。)
所以我提出了这个替代方案:
使用事件,Angular中被遗忘的特性。
JavaScript终究喜欢事件。事件本质上是松散耦合的,更好的是,您可以避免向$摘要中添加另一个$watch。
app.directive('focusOn', function() {
return function(scope, elem, attr) {
scope.$on(attr.focusOn, function(e) {
elem[0].focus();
});
};
});
所以现在你可以这样使用它:
<input type="text" focus-on="newItemAdded" />
然后在应用程序的任何地方。
$scope.addNewItem = function () {
/* stuff here to add a new item... */
$scope.$broadcast('newItemAdded');
};
这太棒了,因为你可以用它做各种各样的事情。首先,你可以把已经存在的事件联系起来。另一方面,你开始做一些聪明的事情,让应用程序的不同部分发布事件,让应用程序的其他部分可以订阅。
无论如何,这种类型的东西对我来说就是“事件驱动”。我认为作为Angular开发人员,我们真的很努力地把$scope形状的钉子钉进事件形状的洞里。
这是最好的解决方案吗?我不知道。这是一个解决方案。
更新的解决方案
在@ShimonRachlenko下面的评论之后,我稍微改变了我的方法。现在我使用服务和指令的组合来处理“幕后”事件:
除此之外,它与上面概述的原理相同。
下面是一个快速的Plunk演示
# # #使用
<input type="text" focus-on="focusMe"/>
app.controller('MyCtrl', function($scope, focus) {
focus('focusMe');
});
# # #源
app.directive('focusOn', function() {
return function(scope, elem, attr) {
scope.$on('focusOn', function(e, name) {
if(name === attr.focusOn) {
elem[0].focus();
}
});
};
});
app.factory('focus', function ($rootScope, $timeout) {
return function(name) {
$timeout(function (){
$rootScope.$broadcast('focusOn', name);
});
}
});