在AngularJS中,“Angular的方法”是什么?

更具体的要求:

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

我尝试用自动对焦来实现第一个要求,但这只在Modal第一次打开时有效,并且只在某些浏览器中有效(例如在Firefox中它不起作用)。


当前回答

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

马克·拉杰科克是…他的答案是一个有效的答案,但它有一个缺陷(对不起,马克)…

…尝试使用布尔值来聚焦输入,然后模糊输入,然后尝试再次使用它来聚焦输入。它不会工作,除非你重置布尔值为假,然后$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);
    });
  }
});

其他回答

如果你正在使用modalInstance并且拥有对象,你可以在打开模式后使用“then”来执行操作。如果你没有使用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,让方法告诉你什么时候可以聚焦;)

希望这对大家有所帮助!:)

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

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

<input focus="someFocusVariable">

如果你在控制器的任何地方设置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);
          })
      }
    }
  });

用法:

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

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

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

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

添加下面的一行指令使得HTML的“autofocus”属性在Angular.js上有效。

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

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

<input type="text" autofocus>

如果所需的焦点元素被注入到指令模板中,前面的所有答案都将不起作用。 下面的指令既适用于简单元素,也适用于指令注入的元素(我用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 />

内部元素的使用示例(通常用于动态注入元素,如directive with template):

<my-directive focus-on-load="input" />

你可以使用任何jQuery选择器来代替“input”