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

更具体的要求:

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

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


当前回答

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

其他回答

我写了一个双向绑定焦点指令,就像最近的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/

不需要创建自己的指令,可以简单地使用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
        };
    }
})();

你可以创建一个指令,将焦点集中在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,因为postlinks只发生在HTML处理中。

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

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

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