在AngularJS中将焦点设置在输入字段上的“角度方式”是什么?
更具体的要求:
- 当一个模态被打开,在一组预定义的焦点
<input>
这里面模态。 - 每次
<input>
都可见(例如,通过单击某些按钮),将焦点放在其上。
我试图达到第一个要求有autofocus
,但只有当模态被打开的第一次,只有在特定的浏览器(如Firefox中这是行不通的)这个作品。
任何帮助将不胜感激。
在AngularJS中将焦点设置在输入字段上的“角度方式”是什么?
更具体的要求:
<input>
这里面模态。<input>
都可见(例如,通过单击某些按钮),将焦点放在其上。我试图达到第一个要求有autofocus
,但只有当模态被打开的第一次,只有在特定的浏览器(如Firefox中这是行不通的)这个作品。
任何帮助将不胜感激。
Answers:
- 打开模态后,将焦点放在此模态内的预定义<input>上。
定义一个指令,并使其$ watch一个属性/触发器,以便它知道何时集中该元素:
Name: <input type="text" focus-me="shouldBeOpen">
app.directive('focusMe', ['$timeout', '$parse', function ($timeout, $parse) {
return {
//scope: true, // optionally create a child scope
link: function (scope, element, attrs) {
var model = $parse(attrs.focusMe);
scope.$watch(model, function (value) {
console.log('value=', value);
if (value === true) {
$timeout(function () {
element[0].focus();
});
}
});
// to address @blesh's comment, set attribute value to 'false'
// on blur event:
element.bind('blur', function () {
console.log('blur');
scope.$apply(model.assign(scope, false));
});
}
};
}]);
$ timeout似乎需要给定模态时间来渲染。
'2。每当<input>变为可见时(例如,通过单击某些按钮),请将焦点设置在它上面。
创建一个基本上与上述指令相似的指令。观察一些scope属性,当它变为true(在ng-click处理程序中设置)时,执行execute element[0].focus()
。根据您的用例,您可能需要也可能不需要$ timeout:
<button class="btn" ng-click="showForm=true; focusInput=true">show form and
focus input</button>
<div ng-show="showForm">
<input type="text" ng-model="myInput" focus-me="focusInput"> {{ myInput }}
<button class="btn" ng-click="showForm=false">hide form</button>
</div>
app.directive('focusMe', function($timeout) {
return {
link: function(scope, element, attrs) {
scope.$watch(attrs.focusMe, function(value) {
if(value === true) {
console.log('value=',value);
//$timeout(function() {
element[0].focus();
scope[attrs.focusMe] = false;
//});
}
});
}
};
});
更新7/2013:我已经看到一些人使用我原来的隔离范围指令,然后在嵌入的输入字段(即模态中的输入字段)方面遇到问题。没有新作用域(或可能新的子作用域)的指令应减轻某些痛苦。因此,以上我更新了不使用隔离范围的答案。以下是原始答案:
1.使用隔离范围的原始答案:
Name: <input type="text" focus-me="{{shouldBeOpen}}">
app.directive('focusMe', function($timeout) {
return {
scope: { trigger: '@focusMe' },
link: function(scope, element) {
scope.$watch('trigger', function(value) {
if(value === "true") {
$timeout(function() {
element[0].focus();
});
}
});
}
};
});
柱塞。
2.使用隔离范围的原始答案:
<button class="btn" ng-click="showForm=true; focusInput=true">show form and
focus input</button>
<div ng-show="showForm">
<input type="text" focus-me="focusInput">
<button class="btn" ng-click="showForm=false">hide form</button>
</div>
app.directive('focusMe', function($timeout) {
return {
scope: { trigger: '=focusMe' },
link: function(scope, element) {
scope.$watch('trigger', function(value) {
if(value === true) {
//console.log('trigger',value);
//$timeout(function() {
element[0].focus();
scope.trigger = false;
//});
}
});
}
};
});
柱塞。
由于我们需要在指令中重置trigger / focusInput属性,因此“ =”用于双向数据绑定。在第一个指令中,“ @”就足够了。还要注意,当使用“ @”时,我们将触发值与“ true”进行比较,因为@始终会产生字符串。
value != "true"
,看来可以解决我的问题。
马克·拉杰科克(Mark Rajcok)是这个人...他的回答是有效的回答,但是有缺陷(对不起马克)...
...尝试使用布尔将焦点放在输入上,然后使输入模糊,然后尝试使用它再次将输入聚焦。除非将布尔值重置为false,然后将$ digest重置为true,否则它将不起作用。即使在表达式中使用字符串比较,也将不得不将字符串更改为$ digest,然后再将其更改。(这已通过模糊事件处理程序解决。)
因此,我提出了这个替代解决方案:
JavaScript毕竟热爱事件。事件本质上是松散耦合的,甚至更好的是,您避免在$ digest中添加另一个$ 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在下面发表评论后,我已经稍微更改了执行此操作的方法。现在,我结合使用服务和处理“幕后”事件的指令:
除此之外,它与上面概述的原理相同。
<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);
});
}
});
$broadcast
,$timeout
则需要将其包装到。否则不错的解决方案。
当您真正需要的是其他一些答案时,我发现这些答案过于复杂
app.directive('autoFocus', function($timeout) {
return {
restrict: 'AC',
link: function(_scope, _element) {
$timeout(function(){
_element[0].focus();
}, 0);
}
};
});
用法是
<input name="theInput" auto-focus>
我们使用超时让dom中的内容呈现,即使它为零,也至少要等待-这样就可以在模式中工作
ng-click
:假设单击ng-click="showInput = !showInput
输入上的按钮。然后,在您的实际输入上添加ng-if="showInput"
。切换按钮将使指令每次重新运行。我在使用时遇到问题,这ng-show
是错误的方法。
HTML有一个属性autofocus
。
<input type="text" name="fname" autofocus>
您还可以使用angular内置的jqlite功能。
angular.element('.selector').trigger('focus');
Looking up elements via selectors is not supported by jqLite!
这很好用,并且有角度地聚焦输入控制
angular.element('#elementId').focus()
尽管这不是完成任务的纯角度方式,但语法遵循角度样式。jQuery间接扮演角色,并使用Angular直接访问DOM(jQLite => JQuery Light)。
如果需要,可以将此代码轻松放入直接访问元素的简单角度指令中。
Looking up elements via selectors is not supported by jqLite!
angular.element
成为的包装$() / jQuery()
。因此,如果没有它,它将无法正常工作,并且您基本上无论如何都只是使用jQuery(但如果我错了,请纠正我)
我认为$ timeout不是将元素聚焦于创建的好方法。这是一种使用内置角度功能的方法,可从角度文档的模糊深度中挖掘出来。请注意,对于链接前和链接后功能,如何将“链接”属性拆分为“前置”和“后置”。
工作示例: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
这是我的原始解决方案:
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。
我写了一个双向绑定焦点指令,就像最近的模型一样。
您可以像这样使用focus指令:
<input focus="someFocusVariable">
如果您使someFocusVariable作用域变量 true
在控制器的任何位置都设置了,则输入将变得集中。如果要“模糊”输入,可以将someFocusVariable设置为false。这就像Mark Rajcok的第一个答案,但具有双向绑定。
这是指令:
function Ctrl($scope) {
$scope.model = "ahaha"
$scope.someFocusVariable = true; // If you want to focus initially, set this to true. Else you don't need to define this at all.
}
angular.module('experiement', [])
.directive('focus', function($timeout, $parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$watch(attrs.focus, function(newValue, oldValue) {
if (newValue) { element[0].focus(); }
});
element.bind("blur", function(e) {
$timeout(function() {
scope.$apply(attrs.focus + "=false");
}, 0);
});
element.bind("focus", function(e) {
$timeout(function() {
scope.$apply(attrs.focus + "=true");
}, 0);
})
}
}
});
用法:
<div ng-app="experiement">
<div ng-controller="Ctrl">
An Input: <input ng-model="model" focus="someFocusVariable">
<hr>
<div ng-click="someFocusVariable=true">Focus!</div>
<pre>someFocusVariable: {{ someFocusVariable }}</pre>
<pre>content: {{ model }}</pre>
</div>
</div>
这是小提琴:
对于那些通过Bootstrap插件使用Angular的用户:
http://angular-ui.github.io/bootstrap/#/modal
您可以opened
了解模式实例的承诺:
modalInstance.opened.then(function() {
$timeout(function() {
angular.element('#title_input').trigger('focus');
});
});
modalInstance.result.then(function ( etc...
$timeout
用50ms
代替0
。
我发现使用通用表达式很有用。这样,您可以执行诸如在输入文本有效时自动移动焦点之类的操作
<button type="button" moo-focus-expression="form.phone.$valid">
或在用户填写固定长度字段时自动聚焦
<button type="submit" moo-focus-expression="smsconfirm.length == 6">
当然,加载后也要集中精力
<input type="text" moo-focus-expression="true">
指令的代码:
.directive('mooFocusExpression', function ($timeout) {
return {
restrict: 'A',
link: {
post: function postLink(scope, element, attrs) {
scope.$watch(attrs.mooFocusExpression, function (value) {
if (attrs.mooFocusExpression) {
if (scope.$eval(attrs.mooFocusExpression)) {
$timeout(function () {
element[0].focus();
}, 100); //need some delay to work with ng-disabled
}
}
});
}
}
};
});
不要复活僵尸或插入我自己的指令(好吧,这正是我在做的事情):
https://github.com/hiebj/ng-focus-if
http://plnkr.co/edit/MJS3zRk079Mu72o5A9l6?p=preview
<input focus-if />
(function() {
'use strict';
angular
.module('focus-if', [])
.directive('focusIf', focusIf);
function focusIf($timeout) {
function link($scope, $element, $attrs) {
var dom = $element[0];
if ($attrs.focusIf) {
$scope.$watch($attrs.focusIf, focus);
} else {
focus(true);
}
function focus(condition) {
if (condition) {
$timeout(function() {
dom.focus();
}, $scope.$eval($attrs.focusDelay) || 0);
}
}
}
return {
restrict: 'A',
link: link
};
}
})();
首先,官方的重点关注方法是1.1的路线图。同时,您可以编写指令以实现设置焦点。
其次,要在当前可见的项目上设置焦点,需要一种解决方法。只需使用延迟对元素focus()的调用即可$timeout
。
因为在聚焦,模糊和选择方面存在相同的controller-modified-DOM问题,所以我建议使用一个ng-target
指令:
<input type="text" x-ng-model="form.color" x-ng-target="form.colorTarget">
<button class="btn" x-ng-click="form.colorTarget.focus()">do focus</button>
此处的角度线程:http : //goo.gl/ipsx4,更多详细信息在此处发布:http : //goo.gl/4rdZa
以下指令将.focus()
根据ng-target
属性指定在控制器内部创建一个函数。(它创建.blur()
和.select()
也。)演示:http://jsfiddle.net/bseib/WUcQX/
ngFocus
似乎是处理方式focus
的事件,而不是一个方法来设置焦点的元素上。
除了创建自己的指令之外,还可以简单地使用javascript函数来完成焦点。
这是一个例子。
在html文件中:
<input type="text" id="myInputId" />
在文件javascript中,例如在控制器中要激活焦点的位置:
document.getElementById("myInputId").focus();
如果您只是想要一个由ng-click控制的简单焦点。
HTML:
<input ut-focus="focusTigger">
<button ng-click="focusTrigger=!focusTrigger" ng-init="focusTrigger=false"></button>
指示:
'use strict'
angular.module('focus',['ng'])
.directive('utFocus',function($timeout){
return {
link:function(scope,elem,attr){
var focusTarget = attr['utFocus'];
scope.$watch(focusTarget,function(value){
$timeout(function(){
elem[0].focus();
});
});
}
}
});
您可以只创建一个指令,以强制关注postLinking上的装饰元素:
angular.module('directives')
.directive('autoFocus', function() {
return {
restrict: 'AC',
link: function(_scope, _element) {
_element[0].focus();
}
};
});
然后在您的html中:
<input type="text" name="first" auto-focus/> <!-- this will get the focus -->
<input type="text" name="second"/>
这适用于模式和ng-if切换元素,不适用于ng-show,因为postLinking仅在HTML处理时发生。
马克和布莱什有很好的答案。但是,Mark的缺点是Blesh指出了(实施起来很复杂),而且我觉得Blesh的答案在创建服务时存在语义错误,该服务专门用于将焦点请求发送到前端,而实际上他需要的只是一种方法。将事件延迟到所有指令都在侦听为止。
因此,这就是我最终要做的事情,它从Blesh的答案中窃取了很多东西,但是将控制器事件和“加载后”服务的语义分开了。
这使控制器事件可以轻松地挂接到除仅关注特定元素之外的事情上,并且还允许仅在需要时才承担“加载后”功能的开销,而在许多情况下可能不需要。
<input type="text" focus-on="controllerEvent"/>
app.controller('MyCtrl', function($scope, afterLoad) {
function notifyControllerEvent() {
$scope.$broadcast('controllerEvent');
}
afterLoad(notifyControllerEvent);
});
app.directive('focusOn', function() {
return function(scope, elem, attr) {
scope.$on(attr.focusOn, function(e, name) {
elem[0].focus();
});
};
});
app.factory('afterLoad', function ($rootScope, $timeout) {
return function(func) {
$timeout(func);
}
});
这也可以使用ngModelController
。使用1.6及更高版本(旧版本不知道)。
的HTML
<form name="myForm">
<input type="text" name="myText" ng-model="myText">
</form>
JS
$scope.myForm.myText.$$element.focus();
-
注意:根据上下文,您可能需要包装超时功能。
注意:使用时controllerAs
,这几乎是相同的。只需在JS name="myForm"
中用name="vm.myForm"
和替换即可vm.myForm.myText.$$element.focus();
。
可能是ES6时代最简单的解决方案。
添加以下一个线性指令可使HTML“ autofocus”属性在Angular.js上有效。
.directive('autofocus', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())}))
现在,您可以使用HTML5自动对焦语法,例如:
<input type="text" autofocus>
.directive('autofocus', ['$timeout', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())})])
这里只是一个新手,但是我很想让这个指令在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.open方法中,我使用以下方法指示应将焦点放在何处的元素:
var d = $modal.open({
controller : function($scope, $modalInstance) {
...
$scope.idToFocus = "cancelaAteste";
}
...
});
在模板上我有这个:
<input id="myInputId" focus />
以下指令对我有用。使用相同的autofocus html属性进行输入。
.directive('autofocus', [function () {
return {
require : 'ngModel',
restrict: 'A',
link: function (scope, element, attrs) {
element.focus();
}
};
}])
如果您正在使用modalInstance并拥有对象,则可以在打开模式后使用“ then”进行操作。如果您不使用modalInstance,并且使用硬编码打开模式,则可以使用该事件。$ timeout不是一个好的解决方案。
您可以执行(Bootstrap3):
$("#" + modalId).on("shown.bs.modal", function() {
angular.element("[name='name']").focus();
});
在modalInstance上,您可以查看库以了解打开模式后如何执行代码。
不要这样使用$ timeout,$ timeout可以是0、1、10、30、50、200或更大,这取决于客户端计算机以及打开模式的过程。
不要使用$ timeout让该方法告诉您何时可以聚焦;)
希望对您有所帮助!:)
如果将所需的焦点元素注入指令模板中,则所有先前的答案均无效。以下指令适合简单元素或指令注入元素(我在typescript中写了它)。它接受内部可聚焦元素的选择器。如果您只需要关注self元素-请勿将任何选择器参数发送到指令:
module APP.Directives {
export class FocusOnLoadDirective implements ng.IDirective {
priority = 0;
restrict = 'A';
constructor(private $interval:any, private $timeout:any) {
}
link = (scope:ng.IScope, element:JQuery, attrs:any) => {
var _self = this;
var intervalId:number = 0;
var clearInterval = function () {
if (intervalId != 0) {
_self.$interval.cancel(intervalId);
intervalId = 0;
}
};
_self.$timeout(function(){
intervalId = _self.$interval(function () {
let focusableElement = null;
if (attrs.focusOnLoad != '') {
focusableElement = element.find(attrs.focusOnLoad);
}
else {
focusableElement = element;
}
console.debug('focusOnLoad directive: trying to focus');
focusableElement.focus();
if (document.activeElement === focusableElement[0]) {
clearInterval();
}
}, 100);
scope.$on('$destroy', function () {
// Make sure that the interval is destroyed too
clearInterval();
});
});
};
public static factory = ():ng.IDirectiveFactory => {
let directive = ($interval:any, $timeout:any) => new FocusOnLoadDirective($interval, $timeout);
directive.$inject = ['$interval', '$timeout'];
return directive;
};
}
angular.module('common').directive('focusOnLoad', FocusOnLoadDirective.factory());
}
简单元素的用法示例:
<button tabindex="0" focus-on-load />
内部元素的用法示例(通常用于带有模板指令的动态注入元素):
<my-directive focus-on-load="input" />
您可以使用任何jQuery选择器代替“输入”
我编辑Mark Rajcok的focusMe指令,以在一个元素中实现多个焦点。
HTML:
<input focus-me="myInputFocus" type="text">
在AngularJs控制器中:
$scope.myInputFocus= true;
AngulaJS指令:
app.directive('focusMe', function ($timeout, $parse) {
return {
link: function (scope, element, attrs) {
var model = $parse(attrs.focusMe);
scope.$watch(model, function (value) {
if (value === true) {
$timeout(function () {
scope.$apply(model.assign(scope, false));
element[0].focus();
}, 30);
}
});
}
};
});
在寻找更好的解决方案而不是找到它之后,我不得不为它做贡献,而不得不创建它。
准则:1.解决方案应独立于父控制器范围,以增加可重用性。2.避免使用$ watch监视某些情况,因为这既慢,又会增加摘要循环的大小,并使测试更加困难。3.避免$ timeout或$ scope。$ apply()触发摘要循环。4.在使用该指令的元素中存在一个输入元素。
这是我最喜欢的解决方案:
指示:
.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>
我希望这会对外面的人有所帮助!
很简单..尝试
html
<select id="ddl00">
<option>"test 01"</option>
</select>
javascript
document.getElementById("ddl00").focus();
如果您希望将重点放在特定元素上,则可以使用以下方法。
创建一个名为的服务focus
。
angular.module('application')
.factory('focus', function ($timeout, $window) {
return function (id) {
$timeout(function () {
var element = $window.document.getElementById(id);
if (element)
element.focus();
});
};
});
从您要呼叫的地方将其注入控制器。
致电此服务。
我认为该指令是不必要的。使用HTML id和class属性选择所需的元素,并使服务使用document.getElementById或document.querySelector来应用焦点(或jQuery等效项)。
标记是标准的HTML / angular指令,带有添加的ID /类供选择
<input id="myInput" type="text" ng-model="myInputModel" />
控制器广播事件
$scope.$emit('ui:focus', '#myInput');
在UI服务中使用querySelector-如果存在多个匹配项(例如由于类),它将仅返回第一个
$rootScope.$on('ui:focus', function($event, selector){
var elem = document.querySelector(selector);
if (elem) {
elem.focus();
}
});
您可能要使用$ timeout()强制进行摘要循环