如何设置输入字段的焦点?

在AngularJS中设置输入字段的“Angular方式”是什么?

更具体的要求:

  1. 打开Modal时,将焦点设置在此Modal中预定义的<input>上。
  2. 每次<input>变得可见时(例如通过单击某个按钮),将焦点设置在它上。

我试图达到第一个要求autofocus,但这只在第一次打开Modal时有效,并且仅在某些浏览器中有效(例如在Firefox中它不起作用)。

642612 次浏览
  1. 当一个模态被打开时,将焦点设置在这个模态中预定义的<输入>上。

定义一个指令并让它$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));
});
}
};
}]);

Plunker

似乎需要超时$来给模态时间来呈现。

'2.'每次<输入>变得可见(例如通过单击某个按钮),将焦点设置在它上。

创建一个与上面类似的指令。观察一些范围属性,当它变为true时(在你的ng单击处理程序中设置它),执行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;
//});
}
});
}
};
});

Plunker


2013年7月更新:我看到一些人使用我原来的隔离作用域指令,然后在嵌入输入字段(即模态中的输入字段)时遇到问题。没有新作用域(或者可能是新的子作用域)的指令应该会减轻一些痛苦。所以上面我更新了答案,不使用隔离作用域。以下是原始答案:

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

Plunker

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

Plunker

由于我们需要重置指令中的触发器/焦点输入属性,'='用于双向数据绑定。在第一个指令中,'@'就足够了。还要注意,当使用'@'时,我们将触发器值与“true”进行比较,因为@总是会产生一个字符串。

首先,官方的对焦方式是在路线图1.1上。同时,您可以编写一条指令来实现设置焦点。

其次,要在项目变得可见后将焦点设置为当前需要一种解决方法。只需使用$timeout延迟对元素焦点()的调用。

因为焦点、模糊和选择存在相同的控制器修改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/

我写了一个双向绑定焦点指令,就像最近的模型一样。

您可以像这样使用焦点指令:

<input focus="someFocusVariable">

如果你在控制器中的任何地方设置了true范围变量,输入就会得到聚焦。如果你想“模糊”你的输入,则可以将其设置为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>

下面是小提琴:

http://fiddle.jshell.net/ubenzer/9FSL4/8/

##(编辑:我在这个解释下面添加了一个更新的解决方案)

他的回答是一个有效的答案,但它已经有一个缺陷(对不起马克)…

…尝试使用布尔值聚焦输入,然后模糊输入,然后尝试使用它再次聚焦输入。除非您将布尔值重置为false,然后重置为$digest,然后将其重置为true,否则它将无法工作。即使您在表达式中使用字符串比较,您也将被迫将字符串更改为其他值$digest,然后将其更改回来。(这已经用blur事件处理程序解决了。)

所以我提出这个替代解决方案:

使用一个事件,Angular被遗忘的特性。

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开发人员,我们非常努力地将$作用域形状的钉锤成事件形状的孔。

这是最好的解决方案吗?我不知道。它是一个解决方案。


更新的解决方案

在@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);
});
}
});

您还可以使用内置在角中的jqlite功能。

angular.element('.selector').trigger('focus');

你可以创建一个指令,强制将焦点集中在post链接上的装饰元素上:

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,因为postLink仅发生在超文本标记语言处理上。

我发现其他一些答案过于复杂,而你真正需要的就是这个

app.directive('autoFocus', function($timeout) {
return {
restrict: 'AC',
link: function(_scope, _element) {
$timeout(function(){
_element[0].focus();
}, 0);
}
};
});

使用是

<input name="theInput" auto-focus>

我们使用超时来让dom渲染中的内容,即使它为零,它至少会等待-这在模态和诸如此类的东西中也是如此

这里只是一个新手,但我能够使用这个指令在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 />

如果您只是想要一个由ng单击控制的简单焦点。

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

Mark和Blesh有很好的答案;然而,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);
}
});

我认为该指令是不必要的。使用超文本标记语言id和class属性来选择所需的元素,并让服务使用document.getElementById或document.query选择器来应用焦点(或jQuery等价物)。

标记是标准的超文本标记语言/角度指令,添加了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()强制执行摘要循环

我不认为$timeout是将元素集中在创建上的好方法。这是一个使用内置角度功能的方法,是从角度文档的黑暗深处挖掘出来的。请注意“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

只是扔在一些咖啡。

app.directive 'ngAltFocus', ->
restrict: 'A'
scope: ngAltFocus: '='
link: (scope, el, attrs) ->
scope.$watch 'ngAltFocus', (nv) -> el[0].focus() if nv

这是我最初的解决方案:

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

超文本标记语言:

<button ng-click="isVisible = !isVisible">Toggle input</button>
<input ng-show="isVisible" auto-focus="\{\{ isVisible }}" value="auto-focus on" />

它做什么:

当输入在ng-show中可见时,它会聚焦输入。这里没有使用$watch或$on。

无需创建自己的指令,只需使用javascript函数即可完成焦点。

这里有一个例子。

在html文件中:

<input type="text" id="myInputId" />

在文件javascript中,例如在要激活焦点的控制器中:

document.getElementById("myInputId").focus();

我编辑了Mark Rajcok的FOCUSME指令,以便在一个元素中实现多个焦点。

超文本标记语言:

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

这工作得很好,一个角度的方式来集中输入控制

angular.element('#elementId').focus()

这虽然不是一个纯粹的角度方式来完成任务,但语法遵循角度风格。JQuery使用Angular(jQLite=>JQuery Light)间接和直接访问DOM。

如果需要,此代码可以很容易地放在一个简单的角度指令中,其中元素可以直接访问。

不确定依赖超时是否是个好主意,但这适用于ng-重复,因为此代码在angularjs更新DOM后运行,因此您要确保所有对象都在那里:

myApp.directive('onLastRepeat', [function () {
return function (scope, element, attrs) {
if (scope.$last) setTimeout(function () {
scope.$emit('onRepeatLast', element, attrs);
}, 1);
};
}]);
//controller for grid
myApp.controller('SimpleController', ['$scope', '$timeout', '$http', function ($scope, $timeout, $http)
{
var newItemRemoved = false;
var requiredAlert = false;
//this event fires up when angular updates the dom for the last item
//it's observed, so here, we stop the progress bar
$scope.$on('onRepeatLast', function (scope, element, attrs) {
//$scope.complete();
console.log('done done!');
$("#txtFirstName").focus();
});
}]);

我想在寻找更好的解决方案而没有找到它之后为这个讨论做出贡献,而是必须创建它。

标准: 1.解决方案应该独立于父控制器范围,以增加可重用性。 2.避免使用$watch来监控某些条件,这既慢,又增加了摘要循环的大小,并使测试更难。 3.避免$timeout或$scope.$应用()触发摘要循环。 4.使用指令的元素中存在一个输入元素open。

这是我最喜欢的解决方案:

指令:

.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>

我希望这将有助于有人在那里!

不要复活僵尸或插入我自己的指令(好吧,这正是我正在做的):

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

对于那些将Angular与Bootstrap插件一起使用的人:

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...

我发现使用通用表达式很有用。这样你就可以在输入文本有效时自动移动焦点

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

以下指令为我提供了技巧。使用相同的自动对焦html属性进行输入。

.directive('autofocus', [function () {
return {
require : 'ngModel',
restrict: 'A',
link: function (scope, element, attrs) {
element.focus();
}
};
}])

如果您使用modalInstance并且拥有打开模态后可以使用“然后”执行操作的对象。如果您不使用modalInstance,并且硬编码以打开模态,您可以使用事件。$timeout不是一个好的解决方案。

你可以这样做(Bootstrap3):

$("#" + modalId).on("shown.bs.modal", function() {
angular.element("[name='name']").focus();
});

在modalInstance,您可以查看库以了解如何在打开modal后执行代码。

不要像这样使用$timeout,$timeout可以是0、1、10、30、50、200或更多,这将取决于客户端计算机和打开模态的过程。

不要使用$timeout让方法告诉你什么时候可以集中注意力;)

希望对你有帮助!:)

超文本标记语言具有属性autofocus

<input type="text" name="fname" autofocus>

http://www.w3schools.com/tags/att_input_autofocus.asp

一个简单的与情态动词一起工作的例子:

.directive('focusMeNow', ['$timeout', function ($timeout)
{
return {
restrict: 'A',


link: function (scope, element, attrs)
{




$timeout(function ()
{
element[0].focus();
});






}
};
}])

示例

<input ng-model="your.value" focus-me-now />

如果所需的焦点元素注入到指令模板中,则前面的所有答案都不起作用。 以下指令适合简单元素或指令注入元素(我在打字稿中写的)。它接受内部可聚焦元素的选择器。如果你只需要关注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选择器而不是“输入”

您可以使用以下指令在html输入中获取bool值以专注于它…

//js file
angular.module("appName").directive("ngFocus", function () {
return function (scope, elem, attrs, ctrl) {
if (attrs.ngFocus === "true") {
$(elem).focus();
}
if (!ctrl) {
return;
}
elem.on("focus", function () {
elem.addClass("has-focus");
scope.$apply(function () {
ctrl.hasFocus = true;
});
});
};
});


<!-- html file -->
<input type="text" ng-focus="boolValue" />

您甚至可以将控制器中的函数设置为ngFocus指令值 注意下面的代码…

<!-- html file -->
<input type="text" ng-focus="myFunc()" />




//controller file
$scope.myFunc=function(){
if(condition){
return true;
}else{
return false;
}
}

此指令在html页面呈现时发生。

这也可以使用ngModelController。使用1.6+(不知道使用旧版本)。

超文本标记语言

<form name="myForm">
<input type="text" name="myText" ng-model="myText">
</form>

JS

$scope.myForm.myText.$$element.focus();

--

注意:根据上下文,您可能需要包装一个超时函数。

注意²:当使用controllerAs时,这几乎是一样的。只需将name="myForm"替换为name="vm.myForm",并在JS中替换为vm.myForm.myText.$$element.focus();

可能是ES6时代最简单的解决方案。

添加以下一个线性指令使超文本标记语言“自动对焦”属性对Angular.js.有效

.directive('autofocus', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())}))

现在,您可以使用HTML5自动对焦语法,例如:

<input type="text" autofocus>

很简单…试试这个

html

<select id="ddl00">
<option>"test 01"</option>
</select>

javascript

document.getElementById("ddl00").focus();

如果您希望将焦点设置在特定元素上,您可以使用以下方法。

  1. 创建一个名为focus的服务。

    angular.module('application')
    .factory('focus', function ($timeout, $window) {
    return function (id) {
    $timeout(function () {
    var element = $window.document.getElementById(id);
    if (element)
    element.focus();
    });
    };
    });
    
  2. Inject it into the controller from where you wish to call.

  3. Call this service.

以编程方式调用元素上的任何操作:单击()、焦点()、选择()…

用法:

<a href="google.com" auto-action="{'click': $scope.autoclick, 'focus': $scope.autofocus}">Link</a>

指令:

/**
* Programatically Triggers given function on the element
* Syntax: the same as for ng-class="object"
* Example: <a href="google.com" auto-action="{'click': autoclick_boolean, 'focus': autofocus_boolean}">Link</a>
*/
app.directive('focusMe', function ($timeout) {
return {
restrict: 'A',
scope: {
autoAction: '<',
},
link: function (scope, element, attr) {
const _el = element[0];
for (const func in scope.autoAction) {
if (!scope.autoAction.hasOwnProperty(func)) {
continue;
}
scope.$watch(`autoAction['${func}']`, (newVal, oldVal) => {
if (newVal !== oldVal) {
$timeout(() => {
_el[func]();
});
}
});
}


}
}
});

要解决此问题,请在控制器中初始化(最好)时设置变量或作为ng-init:

 <input ng-init="autofocus=true" auto-action="{'focus': autofocus}">