Как установить фокус на поле ввода?

721

Что такое способ Angular, чтобы установить фокус на поле ввода в AngularJS?

Более конкретные требования:

  • Когда открывается Modal, установите фокус на предопределенный <input> внутри этого модального файла.
  • Каждый раз <input> становится видимым (например, нажатием кнопки), установите фокус на нем.

Я попытался выполнить первое требование с помощью autofocus, но это работает только тогда, когда модаль открывается впервые и только в некоторых браузерах (например, в Firefox это не работает).

Любая помощь будет оценена.

Теги:
angularjs-directive

34 ответа

530
Лучший ответ
  • Когда модальный режим открыт, установите фокус на предопределенный <input> внутри этого модального файла.

Определите директиву и получите $watch свойство /trigger, чтобы он знал, когда нужно сфокусировать элемент:

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 comment, set attribute value to 'false'
            // on blur event:
            element.bind('blur', function () {
                console.log('blur');
                scope.$apply(model.assign(scope, false));
            });
        }
    };
}]);

Plunker

Тайм-аут $, кажется, необходим, чтобы дать модальное время для рендеринга.

'2'. Everytime <input> становится видимым (например, нажатием какой-либо кнопки), установите фокус на него.

Создайте директиву, по существу подобную той, что указана выше. Посмотрите на свойство scope, и когда оно станет истинным (установите его в обработчике 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>

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


Обновление 7/2013. Я видел, как некоторые люди используют мои исходные директивы выделения, а затем имеют проблемы со встроенными полями ввода (т.е. поле ввода в модальном). Директива, не имеющая новых возможностей (или, возможно, новый охват ребенка), должна облегчить боль. Поэтому выше я обновил ответ, чтобы не использовать области выделения. Ниже приведен оригинальный ответ:

Оригинальный ответ для 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.

Поскольку нам нужно reset свойство trigger/focusInput в директиве, '=' используется для двусторонней привязки данных. В первой директиве "@" было достаточно. Также обратите внимание, что при использовании "@" мы сравниваем значение триггера с "истинным", так как @всегда выводит строку.

  • 0
    Спасибо за Ваш ответ! Хотя это может сработать в данном конкретном случае, я ищу более общее решение этой проблемы (установка фокуса). Это означает, что директива не должна содержать каких-либо жестко закодированных имен (например, shouldBeOpen ).
  • 0
    @ Миша, ладно, я отредактировал свой ответ, сделав директиву более общей, без жестко заданных имен и изолированной области видимости.
Показать ещё 29 комментариев
244

(EDIT: я добавил обновленное решение ниже этого объяснения)

Марк Райкок - человек... и его ответ - правильный ответ, но у него есть дефект (извините Марк)...

... Попробуйте использовать логическое значение, чтобы сфокусироваться на входе, затем размывайте вход, затем попробуйте использовать его, чтобы снова сфокусировать вход. Это не сработает, если вы не reset с логическим значением false, затем $digest, а затем reset вернемся к true. Даже если вы используете сравнение строк в своем выражении, вам придется изменить строку на что-то еще, $digest, а затем изменить ее. (Это было обработано обработчиком размытия).

Поэтому я предлагаю это альтернативное решение:

Использовать событие, забытую функцию Angular.

JavaScript любит события в конце концов. События по своей сути слабо связаны, и даже лучше, вы избегаете добавлять еще $watch к вашему $digest.

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 ниже я изменил свой способ сделать это немного. Теперь я использую комбинацию сервиса и директивы, которая обрабатывает событие "за кадром":

Кроме того, это тот же самый принцип, о котором говорилось выше.

Вот демонстрационный демонстрационный план

Использование

<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);
    });
  }
});
  • 3
    Вам нужно заключить вызов в $broadcast с $timeout если вы хотите, чтобы это работало при входе в контроллер. В противном случае хорошее решение.
  • 0
    @ShimonRachlenko - Спасибо. Но я не уверен, что вы подразумеваете под таймаутом $. Если бы я хотел вещать во время обработки конструктора контроллера, я бы просто вещал прямо сейчас. Тайм-аут не будет ничего делать, кроме как отложить трансляцию до более позднего выполнения в цикле событий.
Показать ещё 12 комментариев
222

Я нашел некоторые другие ответы слишком сложными, когда все, что вам действительно нужно, это

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

используется

<input name="theInput" auto-focus>

Мы используем таймаут, чтобы позволить вещам в dom render, даже несмотря на то, что он равен нулю, он, по крайней мере, ждет этого - таким образом, это работает в модалах и еще что-то еще

  • 7
    Это единственный пример, который работает для меня (через 2 часа застрял на этом). Но как бы вы вызвали это от нажатия на другую кнопку?
  • 1
    Есть несколько способов сделать это, один из возможных способов, который действительно прост и понятен, состоит в том, чтобы в области (контроллер здесь) установить идентификатор элемента, на который вы хотите сфокусироваться, когда вы нажимаете кнопку, затем в Директива просто послушай это. В этом случае вам не нужно было бы размещать директиву где-то конкретно, просто где-то на этой странице (я использовал подобные директивы наблюдателя с успехом в прошлом, особенно с фокусировкой и прокруткой) - тогда если вы ' Вы используете jquery (упростил бы это), просто найдите этот элемент id и сфокусируйте его
Показать ещё 12 комментариев
86

HTML имеет атрибут autofocus.

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

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

  • 0
    это очень хорошо работает на модалы и диалоги. прохладно!
  • 0
    Это прекрасно работает на IE10 +, Firefox, Chrome, но, увы, IE8-9 не поддерживают атрибут автофокуса, поэтому если вам нужно поддерживать более старую директиву IE, то это лучшее решение.
Показать ещё 3 комментария
60

Вы также можете использовать функцию jqlite, встроенную в angular.

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

  • 2
    Без загруженного jquery: angular.forEach (document.querySelectorAll ('. Selector'), function (elem) {elem.focus ();});
  • 28
    Разве это не плохая практика помещать это в контроллер?
Показать ещё 7 комментариев
53

Это хорошо работает и angular способ фокусировки управления вводом

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

Это хотя и не чистый angular способ выполнения задачи, но синтаксис следует за стилем angular. JQuery играет роль косвенно и напрямую обращается к DOM, используя angular (jQLite = > JQuery Light).

При необходимости этот код можно легко поместить в простую директиву angular, где элемент доступен непосредственно.

  • 4
    Это идеальное решение в некоторых случаях для меня.
  • 0
    Я не уверен, что это отличный подход для ViewModel-приложений. В Angular это должно быть сделано с помощью директив.
Показать ещё 6 комментариев
29

Я не думаю, что $timeout - это хороший способ сфокусировать элемент на создании. Вот метод с использованием встроенной функции angular, выкопанной из мрачной глубины документов angular. Обратите внимание, как атрибут "link" можно разделить на "pre" и "post", для функций предварительной ссылки и пост-ссылки.

Рабочий пример: 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

  • 0
    Это намного лучше, чем при использовании тайм-аута. Отлично сработало для меня!
  • 0
    Мне нравится элегантность этого решения. Однако загрузка примера плунжера работала в IE 11 и Chrome 40, но не в Firefox 36.0.1.
Показать ещё 4 комментария
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()});
            });
        }
    };
});

И HTML:

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

Что он делает:

Он фокусирует ввод, когда он становится видимым с помощью ng-show. Здесь нет использования $watch или $.

  • 0
    На самом деле, я считаю, что {{isVisible}} в любом случае создает часы, поэтому выражение «No use of $ watch» неверно.
  • 0
    Да, я думаю, что вы правы. Но это все еще служит простым способом сделать это.
17

Я недавно написал директиву о двухстороннем связывании фокуса, как и модель.

Вы можете использовать директиву focus следующим образом:

<input focus="someFocusVariable">

Если вы someFocusVariable переменной сферы true в любом месте вашего контроллера, вход сфокусироваться. И если вы хотите "размыть" свой ввод, тогда для someFocusVariable можно установить значение false. Это похоже на первый ответ Марка Райкока, но с двусторонним связыванием.

Вот директива:

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/

  • 0
    Это должен быть правильный ответ. Он охватывает все варианты использования.
10

Для тех, кто использует 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...
  • 0
    Хорошо! Однако в моем случае, $timeout с 50ms нужен вместо 0 .
7

Мне было полезно использовать общее выражение. Таким образом, вы можете делать такие вещи, как автоматическое перемещение фокуса, когда текст ввода действителен.

<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
                        }
                    }
                });
            }
        }
    };
});
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
        };
    }
})();
  • 0
    Сейчас я использую эту директиву, и она прекрасно работает, решает общую проблему и не слишком сложна. В поисках решения без тайм-аута. Продолжайте находить комментарии о том, что фокус находится «на дорожной карте» для Angular 1.1 и 1.2, но я использую 2.x и все еще не могу управлять фокусом. Хех.
7

Вместо создания собственной директивы можно просто использовать функции javascript для достижения фокуса.

Вот пример.

В html файле:

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

В файле javascript, например, в контроллере, где вы хотите активировать фокус:

document.getElementById("myInputId").focus();
  • 8
    Это не «угловой путь», и не советуйте людям прикасаться к DOM в своих контроллерах.
  • 9
    У тебя есть мой голос. Да, это не угловой, но это одна строка, по сравнению с 50+ линиями зверей в других ответах. KISS-принцип во всей красе.
Показать ещё 3 комментария
6

Во-первых, официальный способ сделать акцент сделан на дорожной карте для 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>

Angular здесь: http://goo.gl/ipsx4, и более подробная информация приведена здесь: http://goo.gl/4rdZa

Следующая директива создаст функцию .focus() внутри вашего контроллера, как указано вашим атрибутом ng-target. (Он создает также .blur() и .select().) Демо: http://jsfiddle.net/bseib/WUcQX/

  • 0
    +1 для ссылки на дорожную карту. Фактически я только что видел это в документации 1.2, которая все еще считается нестабильной ( docs.angularjs.org/api/ng.directive:ngFocus )
  • 27
    @EdwinDalorzo ngFocus - это способ обработки событий focus , а не способ установить фокус на элементе.
4

Простой, который хорошо работает с модалами:

.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 />
  • 1
    Абсолютно идеально - спасибо.
  • 0
    Отлично для меня. Спасибо
4

Если вам просто нужен простой фокус, который контролируется ng-click.

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();
                });
            });
        }
    }
});
  • 2
    Испытано около 8 разных примеров, в том числе и этот, ни один из которых не имеет никакого эффекта, но ошибки нет. Есть ли какая-то неустановленная библиотека / зависимость, которую мне нужно загрузить?
3

Возможно, самое простое решение в эпоху ES6.

Добавление следующей директивы liner делает атрибут "автофокусировки" HTML эффективным на Angular.js.

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

Теперь вы можете просто использовать синтаксис автофокуса HTML5, например:

<input type="text" autofocus>
  • 1
    Сначала у меня не получился ответ, нужно было указать зависимость $ timeout.
  • 0
    @Stephane да, тогда он становится .directive('autofocus', ['$timeout', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())})])
3

Это также можно использовать ngModelController. Работа с 1.6+ (не знаю со старыми версиями).

HTML

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

JS

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

-

N.B.: В зависимости от контекста вам, возможно, придется перевернуть функцию тайм-аута.

N.B.²: При использовании controllerAs это почти то же самое. Просто замените name="myForm" на name="vm.myForm" и в JS, vm.myForm.myText.$$element.focus();.

3

У Марка и Блеста есть отличные ответы; однако у Марка есть недостаток, который указывает Блеш (помимо того, что он сложный для реализации), и я чувствую, что ответ 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);
  }
});
  • 0
    Единственный ответ, который я (полный новичок) мог понять. Вместо «afterLoad (notifyControllerEvent);» я использовал «notifyControllerEvent ()». В противном случае все закончилось некоторыми ошибками.
3

Вы можете просто создать директиву, которая заставляет фокус на украшенный элемент на 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 toggled элементов, а не для ng-show, поскольку postLinking происходит только при обработке HTML.

2

Все предыдущие ответы не работают, если желаемый элемент фокусировки вводится в шаблон директивы. Следующая директива соответствует как элементам с простым элементом, так и директивой (я написал это в 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 />

пример использования для внутреннего элемента (обычно для динамического вложенного элемента, такого как директива с шаблоном):

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

вы можете использовать любой селектор jQuery вместо "ввода"

  • 0
    Этот код сделал мою жизнь лучше. Спасибо.
2

Если вы используете modalInstance и имеете объект, вы можете использовать "then" для выполнения действий после открытия модального. Если вы не используете modalInstance и жестко закодированы для открытия модального, вы можете использовать это событие. Тайм-аут $не является хорошим решением.

Вы можете сделать (Bootstrap3):

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

В modalInstance вы можете посмотреть на библиотеку, как выполнить код после открытого модала.

Не используйте $timeout, как это, $timeout может быть 0, 1, 10, 30, 50, 200 или более, это будет зависеть от клиентского компьютера и процесс для открытия модального.

Не используйте $timeout, если метод подскажет вам, когда вы можете сфокусироваться;)

Я надеюсь, что эта помощь!:)

2

Следующая директива сделала трюк для меня. Используйте тот же атрибут html автофокуса для ввода.

.directive('autofocus', [function () {
    return {
        require : 'ngModel',
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.focus();
        }
    };
}])
  • 1
    вы получите ошибку при выполнении этого, если не включен jQuery, вместо этого он должен быть element [0] .focus ()
2

Я редактирую директиву 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);
                }
            });
        }
    };
});
2

Просто новичок здесь, но я не мог заставить его работать в 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 />
1

Это легко.. попробуйте это

HTML

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

Javascript

document.getElementById("ddl00").focus();
  • 0
    Это правильно вне контекста, но не AngularJS способ делать вещи
1

Я хочу внести свой вклад в это обсуждение после поиска в лучшем решении и не находить его, создав его вместо этого.

Критерии: 1. Решение должно быть независимым от возможностей родительского контроллера, чтобы увеличить повторное использование. 2. Избегайте использования $watch для отслеживания некоторых условий, это медленное, увеличивает размер цикла дайджеста и упрощает тестирование. 3. Избегайте $timeout или $scope. $Apply() запускает цикл дайджеста. 4. Элемент ввода присутствует в элементе, где используется Директива.

Это решение, которое мне больше всего понравилось:

Директива:

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

Я надеюсь, что это поможет кому-то!

  • 0
    Это не работает для меня.
  • 0
    Вы просто воссоздали, что делает html «label», вы можете просто заменить «div focus-input» на «label» и избавиться от директивы.
0

Программно вызвать любое действие над элементом: click(), focus(), select()...

Использование:

<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}">
0

Чисто-независимое от фреймворка решение javascript:

Дайте форму, подобную этой:

<form name="myform">
    <input name="search" type="text">
</form>

Вы можете установить фокус с помощью:

document.myform.search.focus();
0

Если вы хотите установить фокус на конкретный элемент, вы можете использовать подход ниже.

  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. Введите его в контроллер, откуда вы хотите позвонить.

  3. Позвоните в эту службу.

0

вы можете использовать директиву ниже, которая получает значение bool в html-вводе для фокусировки на нем...

//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-страницы.

0

Не уверен, что если полагаться на тайм-аут, это хорошая идея, но это работает для ng-repeat, потому что этот код запускается ПОСЛЕ 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 observed, so here, we stop the progress bar
        $scope.$on('onRepeatLast', function (scope, element, attrs) {
            //$scope.complete();
            console.log('done done!');
            $("#txtFirstName").focus();
        });
    }]);
0

Просто бросьте кофе.

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

Я думаю, что директива не нужна. Используйте атрибуты HTML и атрибуты класса, чтобы выбрать нужный элемент и использовать службу document.getElementById или document.querySelector для применения фокуса (или эквивалентов jQuery).

Разметка - это стандартные директивы HTML/ angular с добавлением id/classes для выбора

<input id="myInput" type="text" ng-model="myInputModel" />

Контроллер передает события

$scope.$emit('ui:focus', '#myInput');

В службе пользовательского интерфейса используется querySelector - если существует несколько совпадений (например, из-за класса), он возвращает только первый

$rootScope.$on('ui:focus', function($event, selector){
  var elem = document.querySelector(selector);
  if (elem) {
    elem.focus();
  }
});

Вы можете использовать $timeout(), чтобы заставить цикл дайджеста

Ещё вопросы

Сообщество Overcoder
Наверх
Меню