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

Mis*_*hko 753 angularjs angularjs-directive

在AngularJS中设置焦点到输入字段的"角度方式"是什么?

更具体的要求:

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

我试图达到第一个要求autofocus,但只有当模态被打开的第一次,只有在特定的浏览器(如Firefox中这是行不通的)这个作品.

任何帮助将不胜感激.

Mar*_*cok 575

  1. 打开模态时,将焦点设置在此模态内的预定义<input>上.

定义一个指令并让它$ watch一个属性/触发器,以便知道何时聚焦元素:

Name: <input type="text" focus-me="shouldBeOpen">
Run Code Online (Sandbox Code Playgroud)

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));
            });
        }
    };
}]);
Run Code Online (Sandbox Code Playgroud)

Plunker

似乎需要$ timeout来给出模态时间来渲染.

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

创建一个基本上与上面相似的指令.观察一些范围属性,当它变为真时(在你的ng-click处理程序中设置它),执行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>
Run Code Online (Sandbox Code Playgroud)

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;
          //});
        }
      });
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

Plunker


2013年7月更新:我见过一些人使用我原来的隔离范围指令,然后遇到嵌入式输入字段的问题(即模态中的输入字段).没有新范围(或可能是新的子范围)的指令应该可以缓解一些痛苦.所以上面我更新了不使用隔离范围的答案.以下是原始答案:

原始答案为1.,使用隔离范围:

Name: <input type="text" focus-me="{{shouldBeOpen}}">
Run Code Online (Sandbox Code Playgroud)

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(); 
          });
        }
      });
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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;
          //});
        }
      });
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

Plunker.

由于我们需要重置指令中的trigger/focusInput属性,因此'='用于双向数据绑定.在第一个指令中,'@'就足够了.另请注意,使用'@'时,我们将触发值与"true"进行比较,因为@始终会生成一个字符串.

  • 嗯我的代码工作,因为在我可以看到它正确执行,元素[0]是正确的控制.但.focus()不会触发焦点.可能引导或其他东西干扰这个? (3认同)
  • 另请参阅@Josh 的“焦点”指令:http://stackoverflow.com/a/14859639/215945 他在实现中没有使用隔离范围。 (2认同)
  • @MarkRajcok对这个很好奇:这个版本有效,但是如果我在输入字段上设置了一个`ng-model`,那么当我使用这个指令w /使用isolate范围时,模型值会丢失.如果我在隔离范围内尝试Josh的版本,问题就不会发生.还是一个新手,我想了解其中的差异.[这是一个Plunker](http://plnkr.co/edit/oK53wl?p=preview)显示它. (2认同)
  • 我发现 #1 与 AngularJS 1.0.6 配合得很好。然而,当在调试器下运行时,我注意到每次我关闭并重新打开模式时,我都会看到比之前多了一次对设置焦点的函数的调用。我稍微修改了该函数,以在“value!=“true””时解除手表绑定,这似乎解决了我的问题。 (2认同)
  • @IanB 如果 attrs.focusMe 是表达式而不仅仅是变量名称,则模糊事件“修复”失败(model.assign 不是函数)。例如,它适用于:focus-me="pageActive" 但失败了:focus-me="pageActive==true" (2认同)

Ben*_*esh 262

(编辑:我在此解释下添加了更新的解决方案)

Mark Rajcok是男人......他的答案是一个有效的答案,但它一个缺陷(对不起Mark)......

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

所以我建议这个替代解决方案:

使用事件,Angular的遗忘功能.

毕竟JavaScript喜欢事件.事件本质上是松耦合的,甚至更好,你避免在$ digest中添加另一个$ watch.

app.directive('focusOn', function() {
   return function(scope, elem, attr) {
      scope.$on(attr.focusOn, function(e) {
          elem[0].focus();
      });
   };
});
Run Code Online (Sandbox Code Playgroud)

所以现在你可以像这样使用它:

<input type="text" focus-on="newItemAdded" />
Run Code Online (Sandbox Code Playgroud)

然后在你的应用程序的任何地方

$scope.addNewItem = function () {
    /* stuff here to add a new item... */

    $scope.$broadcast('newItemAdded');
};
Run Code Online (Sandbox Code Playgroud)

这很棒,因为你可以用这样的东西做各种各样的事情.首先,您可以绑定已经存在的事件.另一方面,您可以通过让应用的不同部分发布应用的其他部分可以订阅的事件来开始做一些聪明的事情.

无论如何,这种类型的东西尖叫着"事件驱动"给我.我认为,作为Angular开发人员,我们非常努力地将范围形状的钉子敲入事件形状孔.

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


更新方案

在@ ShimonRachlenko的评论之后,我已经改变了我的方法.现在我使用服务和处理"幕后"事件的指令的组合:

除此之外,它与上面概述的相同.

这是一个快速演示Plunk

用法

<input type="text" focus-on="focusMe"/>
Run Code Online (Sandbox Code Playgroud)
app.controller('MyCtrl', function($scope, focus) {
    focus('focusMe');
});
Run Code Online (Sandbox Code Playgroud)

资源

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);
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 如果你想让它进入控制器,你需要用'$ timeout`来调用`$ broadcast`.不错的解决方案. (3认同)
  • 你说的没错.我想我没有用它专注于负载.我会用更强大的东西来更新答案. (2认同)

小智 241

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

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

用法是

<input name="theInput" auto-focus>
Run Code Online (Sandbox Code Playgroud)

我们使用超时来让dom渲染中的东西,即使它是零,它至少等待它 - 这种方式适用于模态和其他什么

  • 如果输入位于弹出模式中,则零超时的解决方案对我不起作用.但即便是10毫秒也解决了这个问题 (14认同)
  • 对于像@Ade 这样想要通过简单的 `ng-click` 使用它的人来说:假设单击一个按钮在你的输入上有 `ng-click="showInput = !showInput`。然后,在你的实际输入中,添加 ` ng-if="showInput"`。切换按钮将使指令每次重新运行。我遇到了这个问题,因为我使用的是错误的方法 `ng-show`。 (2认同)

Ray*_*tor 90

HTML有一个属性autofocus.

<input type="text" name="fname" autofocus>
Run Code Online (Sandbox Code Playgroud)

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

  • 不幸的是,这只能运作一次.我在Angular [编辑到位](http://stackoverflow.com/a/15453512/1683718)的情况下使用了它,它在Chrome中第一次运行得很好,而在Firefox中根本没有.在Chrome中,当我点击其他项目进行编辑,或者甚至再次在同一项目上时,它不再获得焦点.文档声明它适用于页面加载,只在Angular应用程序中发生一次.如果只是这么简单,我们都会坐在20%的海滩上! (29认同)

Jor*_*anC 62

您还可以使用内置于angular中的jqlite功能.

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

  • 将它放入控制器不是一个坏习惯吗? (29认同)
  • 我明白了:"jqLit​​e不支持通过选择器查找元素!" (3认同)
  • 没有加载jquery:angular.forEach(document.querySelectorAll('.selector'),function(elem){elem.focus();}); (2认同)
  • 如果将这个jqlite行放在控制器中是不好的做法,将这个jqlite行放在一个指令中会不会更好? (2认同)

San*_*ngh 55

这很有效,也是一种聚焦输入控制的角度方式

angular.element('#elementId').focus()
Run Code Online (Sandbox Code Playgroud)

这虽然不是完成任务的纯粹角度方式,但语法遵循角度样式.Jquery使用Angular(jQLite => JQuery Light)间接地扮演角色并直接访问DOM.

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

  • 据我所知,你需要首先加载jQuery作为依赖,在这种情况下`angular.element`成为`$()/ jQuery()`的包装器.所以没有它,这将无法工作,你基本上只是使用jQuery(但如果我错了,请纠正我) (6认同)

Cod*_*niz 31

我不认为$ 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();
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)
<input value="hello" />
<!-- this input automatically gets focus on creation -->
<input value="world" auto-focus />
Run Code Online (Sandbox Code Playgroud)

完整的AngularJS指令文档:https://docs.angularjs.org/api/ng/service/$compile

  • 不得不将元素[0] .focus()包装在$ timeout中以使其适用于我. (2认同)
  • 根据文档,“链接”函数默认为“postLink”。另见:http://www.bennadel.com/blog/2746-the-post-link-function-is-the-link-function-in-angularjs-directives.htm (2认同)

Umu*_*zer 17

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

您可以像这样使用focus指令:

<input focus="someFocusVariable">
Run Code Online (Sandbox Code Playgroud)

如果true在控制器的任何位置创建someFocusVariable范围变量,输入将得到集中.如果你想"模糊"输入,那么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);
          })
      }
    }
  });
Run Code Online (Sandbox Code Playgroud)

用法:

<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>
Run Code Online (Sandbox Code Playgroud)

这是小提琴:

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


Edh*_*ler 17

这是我原来的解决方案:

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()});
            });
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

和HTML:

<button ng-click="isVisible = !isVisible">Toggle input</button>
<input ng-show="isVisible" auto-focus="{{ isVisible }}" value="auto-focus on" />
Run Code Online (Sandbox Code Playgroud)

它能做什么:

它通过ng-show变为可见的输入.这里没有使用$ watch或$.


BPH*_*BPH 11

对于那些将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...
Run Code Online (Sandbox Code Playgroud)


win*_*nry 8

我发现使用通用表达式很有用.通过这种方式,您可以在输入文本有效时执行自动移动焦点等操作

<button type="button" moo-focus-expression="form.phone.$valid">
Run Code Online (Sandbox Code Playgroud)

或者在用户完成固定长度字段时自动对焦

<button type="submit" moo-focus-expression="smsconfirm.length == 6">
Run Code Online (Sandbox Code Playgroud)

当然,重点是加载后

<input type="text" moo-focus-expression="true">
Run Code Online (Sandbox Code Playgroud)

指令的代码:

.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
                        }
                    }
                });
            }
        }
    };
});
Run Code Online (Sandbox Code Playgroud)


小智 7

您可以简单地使用javascript函数来完成焦点,而不是创建自己的指令.

这是一个例子.

在html文件中:

<input type="text" id="myInputId" />
Run Code Online (Sandbox Code Playgroud)

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

document.getElementById("myInputId").focus();
Run Code Online (Sandbox Code Playgroud)

  • 这不是一种"角度方式",也不建议人们在控制器中触摸DOM. (9认同)

Jon*_*ieb 7

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

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
        };
    }
})();
Run Code Online (Sandbox Code Playgroud)


bro*_*eib 6

首先,关注的官方方法是1.1路线图.同时,您可以编写指令来实现设置焦点.

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

因为对焦点,模糊和选择存在相同的controller-modifies-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>
Run Code Online (Sandbox Code Playgroud)

Angular线程在这里:http://goo.gl/ipsx4,更多细节在这里博客:http://goo.gl/4rdZa

以下指令将.focus()在您的控制器内创建一个由您的ng-target属性指定的函数.(它创建了一个.blur()和一个.select().)演示:http://jsfiddle.net/bseib/WUcQX/

  • @EdwinDalorzo`ngFocus`似乎是处理`focus`事件的一种方式,而不是**设置**关注元素的方法. (27认同)

TOB*_*der 5

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

网址:

<input ut-focus="focusTigger">

<button ng-click="focusTrigger=!focusTrigger" ng-init="focusTrigger=false"></button>
Run Code Online (Sandbox Code Playgroud)

指示:

'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();
                });
            });
        }
    }
});
Run Code Online (Sandbox Code Playgroud)