Установка фокуса на поле ввода после ng-show

#angularjs #angularjs-scope

#angularjs #angularjs-область

Вопрос:

Возможно ли установить фокус поля ввода через контроллер после загрузки данных (в данном случае через $resource)?

Ввод скрыт с помощью ng-show до тех пор, пока данные не будут возвращены из API, но я не могу найти способ установить фокус на ввод. Я знаю имя ng-model для ввода и имя ввода, что означает, что я мог бы сделать это с помощью jQuery, но я бы предпочел сделать это, если возможно, с помощью AngularJS.

Я перепробовал здесь много примеров директив, но все они, похоже, ориентированы на ng-фокус до 1.2, полагаются на ng-щелчок сначала с кнопки (в моем случае этого не может быть) или просто не работают.
Любые советы с благодарностью получены.

Комментарии:

1. Если вы делаете это при загрузке страницы, некоторые браузеры не позволят вам сделать это по соображениям безопасности.

2. Я надеюсь, что нет, я бы предпочел отключить вызов, когда я знаю, что данные вернулись из API, но я не вижу, как заставить это работать даже с помощью jQuery.

Ответ №1:

Это простая директива, которая может сработать для вас

 <input focus-on="!!myResourceData" />

.directive('focusOn',function($timeout) {
    return {
        restrict : 'A',
        link : function($scope,$element,$attr) {
            $scope.$watch($attr.focusOn,function(_focusVal) {
                $timeout(function() {
                    _focusVal ? $element[0].focus() :
                        $element[0].blur();
                });
            });
        }
    }
})
 

Комментарии:

1. Да! Вот и все — возможно, я делал это неправильно, поскольку я видел что-то подобное, но не использовался!! в теге HTML. Спасибо 🙂

2. Почему setTimeout ? Это потому, что этот цикл дайджеста еще не показывает элемент? $timeout это было бы чисто выполнено, не прибегая к произвольным временам.

3. @spenhil- вы совершенно правы. Я обновил пример. Спасибо.

4. Я не знаю, связано ли это с тем, что я использовал другую версию angular или что-то еще, но мне пришлось изменить $element.focus() $element[0].focus() и то же самое blur() , прежде чем это сработало. Кроме этого, это спасло мне день.

5. Вам также может потребоваться установить $element[0].select() , но самая большая проблема заключается в том, что он, скорее всего, не будет работать без указания задержки по времени ожидания, так как оба ng-hide и ng-show отображаются с определенной анимацией (ng-hide-animate), поэтому в течение переходного периода вы не сможете установить фокус. В идеале вы должны получить переходный период от элемента, но я надеюсь, что указание некоторой фиксированной (50 мс) задержки может сработать и для вас.

Ответ №2:

Я расширил ответ для работы с angular ng-show и ng-hide

 app.directive('focusOnShow', function($timeout) {
    return {
        restrict: 'A',
        link: function($scope, $element, $attr) {
            if ($attr.ngShow){
                $scope.$watch($attr.ngShow, function(newValue){
                    if(newValue){
                        $timeout(function(){
                            $element[0].focus();
                        }, 0);
                    }
                })      
            }
            if ($attr.ngHide){
                $scope.$watch($attr.ngHide, function(newValue){
                    if(!newValue){
                        $timeout(function(){
                            $element[0].focus();
                        }, 0);
                    }
                })      
            }

        }
    };
})
 

Все, что вам нужно, это добавить атрибут focus-on-show

 <input type="text" ng-show="editing" focus-on-show />
 

Комментарии:

1. Это ИМЕННО то, что я искал, потрясающий код, который вы там сделали! Поздравляю!

2. Именно то, что я искал, это единственный ответ, который работает до сих пор

3. Это отлично работает в браузере, но на iPhone оно не работает

Ответ №3:

Основываясь на ответе koolunix, если вы хотите сфокусировать только элементы ввода, также может быть полезно найти первый элемент ввода, который является дочерним элементом элемента с директивой focus-on .

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

 .directive('focusOn', function ($timeout) {
    return {
        restrict: 'A',
        priority: -100,
        link: function ($scope, $element, $attr) {

            $scope.$watch($attr.focusOn,
                function (_focusVal) {
                    $timeout( function () {
                        var inputElement = $element.is('input')
                            ? $element
                            : $element.find('input');

                         _focusVal ? inputElement.focus()
                                   : inputElement.blur();
                    });
                }
            );

        }
    };
});
 

Ответ №4:

вы должны использовать тайм-аут в своем контроллере, чтобы он был отображен до того, как вот аналогичный пример с полем поиска, которое скрыто по умолчанию

HTML:

 <input ng-show="vm.isActive" id="searchInputBox" ></input>
<input type="button" ng-click="vm.toggleActiveInactive();">
 

Контроллер:

 vm.isActive=false;
vm.toggleActiveInactive=toggleActiveInactive; // vm= viewmodel

function toggleActiveInactive() {
          if(vm.isActive==true){
            vm.isActive=false;
          }else{
            vm.isActive=true;

            $timeout(function(){     
              document.getElementById('searchBoxInput').focus()
            }, 10 );

          }
        }
 

Ответ №5:

Другая версия этого для Angular.io

 import {Directive, ElementRef, Input, OnChanges, SimpleChanges} from '@angular/core';

//Directive to that toggles focus from boolean value set with focusOn
@Directive({
  selector: '[focusOn]'
})
export class FocusOnDirective implements OnChanges {
  @Input('focusOn') setFocus: boolean;

  constructor(private hostElement: ElementRef) {}

  ngOnChanges(changes : SimpleChanges) {
    (!!changes.setFocus amp;amp; !!changes.setFocus.currentValue) ?
      this.hostElement.nativeElement.focus() :
      this.hostElement.nativeElement.blur();
  }
}