如何把重点放在input字段?
在AngularJS中,关注input字段的“angular度方式”是什么?
更具体的要求:
- 当一个模态被打开时,把焦点设置在这个模态内的一个预定义的
<input>
。 - 每次
<input>
变得可见(例如通过点击某个button),将焦点放在它上面。
我试图用autofocus
来实现第一个要求 ,但是这只在第一次打开Modal时才有效,并且只在某些浏览器中(例如在Firefox中不起作用)。
任何帮助将不胜感激。
- 当一个Modal被打开时,将焦点设置在这个Modal中的一个预定义的<input>上。
定义一个指令并让它看$一个属性/触发器,以便知道何时聚焦该元素:
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”。 每次<input>变得可见(例如通过点击某个button),将焦点放在它上面。
创build一个基本上像上面的指令。 观察一些scope属性,当它成为true(在ng-click处理程序中设置它)时,执行element[0].focus()
。 根据您的使用情况,您可能需要或不需要$超时这个:
<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月更新 :我看到一些人使用我的原始隔离范围指令,然后有embedded式input字段(即模态中的input字段)的问题。 没有新范围(或可能是新的子范围)的指令应该可以减轻一些痛苦。 所以上面我更新了答案,不使用隔离范围。 以下是原来的答案:
原始答案为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 。
由于我们需要重置指令中的trigger / focusInput属性,“=”用于双向数据绑定。 在第一个指令中,“@”就足够了。 还要注意,当使用'@'时,我们将触发值与“true”进行比较,因为@总是产生一个string。
(编辑:我在这个解释下面添加了一个更新的解决scheme)
马克Rajcok是男人…他的回答是一个有效的答案,但它有一个缺陷(对不起马克)…
…尝试使用布尔值来聚焦input,然后模糊input,然后尝试使用它来再次聚焦input。 除非将布尔值重置为false,然后$ digest,否则它将不起作用,然后将其重置为true。 即使你在你的expression式中使用了一个string比较,你也会被迫把string改为$ digest,然后改回来。 (这已通过模糊事件处理程序解决。)
所以我提出这个备用解决scheme:
使用一个事件,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开发者,我们非常努力地将$形状的钉子钉入事件形状的洞中。
这是最好的解决scheme吗? 我不知道。 这是一个解决scheme。
更新解决scheme
在下面的@ 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); }); } });
当你真正需要的是这样的时候,我发现其他一些答案会过于复杂
app.directive('autoFocus', function($timeout) { return { restrict: 'AC', link: function(_scope, _element) { $timeout(function(){ _element[0].focus(); }, 0); } }; });
用法是
<input name="theInput" auto-focus>
我们使用超时在dom渲染的东西,即使它是零,至less在等待 – 这样,这种方式工作在莫代尔什么也不
HTML有一个属性autofocus
。
<input type="text" name="fname" autofocus>
您还可以使用内置到angular度的jqlitefunction。
angular.element('.selector').trigger('focus');
这可以很好地工作,并且是一种集中input控制的angular度
angular.element('#elementId').focus()
这虽然不是完成任务的纯粹的angular度方式,但是其语法遵循angular度风格。 jquery间接地使用Angular(jQLite => JQuery Light)直接访问DOM。
如果需要的话,这个代码可以很容易地放在一个简单的angular度指令中,其中元素是可以直接访
我不认为$超时是一个很好的方法来关注创build元素。 这里是一个使用内置angularfunction的方法,从angular度文档的黑暗深度挖掘出来。 请注意,链接属性可以分为“前”和“后”,用于链接前链接和后链接function。
工作示例: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
这是我原来的解决scheme:
plunker
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显示input时,它将input的焦点集中在一起。 这里没有使用$ watch或$。
我写了一个双向绑定焦点指令,就像最近的模型一样。
你使用像这样的焦点指令:
<input focus="someFocusVariable">
如果您在控制器的任何位置使某些FocusVariable范围variables为true,则input焦点。 如果你“模糊”你的input,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>
这是小提琴:
对于那些使用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...
而不是创build自己的指令,可以简单地使用JavaScript函数来完成重点。
这是一个例子。
在html文件中:
<input type="text" id="myInputId" />
在一个文件的JavaScript中,例如,在一个控制器中,你想激活焦点:
document.getElementById("myInputId").focus();
不要复活僵尸或插入我自己的指令(好吧,这正是我在做什么):
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的路线图 。 同时,你可以写一个指令来实现设置重点。
其次,为了在项目变得可见之后设置焦点,需要一个解决方法。 只需延迟调用元素焦点() $timeout
。
由于相同的控制器修改DOM问题存在焦点,模糊和select,我build议有一个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>
Angular的线程在这里: http : //goo.gl/ipsx4 ,更详细的博客在这里: http : //goo.gl/4rdZa
下面的指令将在您的控制器中创build一个.focus()
函数,如ng-target
属性所指定。 (它.blur()
创build.blur()
和.select()
。)演示: http : //jsfiddle.net/bseib/WUcQX/
我发现使用一般expression式是有用的。 这样你就可以做类似于input文本有效时自动移动焦点的东西
<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 } } }); } } }; });
如果你只是想要一个简单的焦点,由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(); }); }); } } });
一个简单的,与模式运作良好:
.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 />
您可以创build一个强制关注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 – 如果切换的元素,而不是ng-show,因为postLinking只发生在HTML处理。
马克和布莱斯有很好的答案。 然而,Mark's有一个缺点,Blesh指出(除了复杂的实现),我觉得Blesh的答案在创build服务时存在语义上的错误,特别是向前端发送焦点请求时,他真正需要的是一种方法延迟事件,直到所有的指令都在收听。
所以这就是我最终做的事情,从Blesh的回答中窃取了很多,但是把控制器事件的语义和“后装”服务分开。
这允许控制器事件很容易被钩住,而不仅仅是聚焦一个特定的元素,并且还允许仅在需要时引起“后装”function的开销,这在许多情况下可能不是这样。
用法
<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); } });
在这里只是一个新手,但我很有能力使用这个指令在一个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 />
我编辑了“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); } }); } }; });
下面的指令为我做了诀窍。 使用相同的自动对焦html属性进行input。
.directive('autofocus', [function () { return { require : 'ngModel', restrict: 'A', link: function (scope, element, attrs) { element.focus(); } }; }])
如果你正在使用modalInstance并且有对象,你可以使用“然后”在打开模式之后执行操作。 如果你没有使用modalInstance,而硬编码打开模式,你可以使用该事件。 $超时不是一个好的解决scheme。
你可以做(Bootstrap3):
$("#" + modalId).on("shown.bs.modal", function() { angular.element("[name='name']").focus(); });
在modalInstance中,您可以查看库在打开模式之后如何执行代码。
不要像这样使用$ timeout,$ timeout可以是0,1,10,30,50,200或更多,这取决于客户端计算机,以及打开模式的过程。
不要使用$超时让方法告诉你什么时候可以关注;)
我希望这个帮助! 🙂
如果所需的焦点元素被注入到指令模板中,所有以前的答案都不起作用。 下面的指令适合简单的元素或指令注入元素(我在打字稿中写到)。 它接受内部可对焦元素的select器。 如果你只需要关注self元素 – 不要发送任何select器参数给指令:
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 />
内部元素的使用示例(通常用于dynamic注入的元素,如带模板的指令):
<my-directive focus-on-load="input" />
你可以使用任何jQueryselect器而不是“input”
这也可以使用ngModelController
。 使用1.6+(不知道与旧版本)。
HTML
<form name="myForm"> <input type="text" name="myText" ng-model="myText"> </form>
JS
$scope.myForm.myText.$$element.focus();
–
注意:根据上下文的不同,你可能需要使用超时function。
NB²:使用controllerAs
,这几乎是一样的。 只需将name="myForm"
replacename="myForm"
name="vm.myForm"
然后在JS中使用vm.myForm.myText.$$element.focus();
。
我想在寻找更好的解决scheme并找不到它的时候,为这个讨论做出贡献,而不是去创造它。
标准:1.解决scheme应该独立于父控制器的范围,以提高可重用性。 2.避免使用$ watch监视某些情况,这样做速度很慢,增加了摘要循环的大小,使testing变得更加困难。 3.避免$ timeout或$ scope。$ apply()来触发摘要循环。 4.使用指令的元素中存在一个input元素。
这是我最喜欢的解决scheme:
指示:
.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>
我希望这会帮助那里的人!
可能是ES6时代最简单的解决scheme。
添加下面的一个线性指令使得在Angular.js上HTML'autofocus'属性有效。
.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();
我认为这个指令是不必要的。 使用HTML ID和类属性来select所需的元素,并让服务使用document.getElementById或document.querySelector来应用焦点(或jQuery等价物)。
标记是标准的HTML /angular度指令与添加id /类的select
<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()来强制一个摘要循环
只要投入一些咖啡。
app.directive 'ngAltFocus', -> restrict: 'A' scope: ngAltFocus: '=' link: (scope, el, attrs) -> scope.$watch 'ngAltFocus', (nv) -> el[0].focus() if nv
不确定是否依赖超时是一个好主意,但这适用于ng-repeat,因为此代码在AFTER之后运行更新了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(); }); }]);