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

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

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

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


person Chris Southam    schedule 25.06.2014    source источник
comment
Если вы делаете это при загрузке страницы, некоторые браузеры не позволят вам сделать это из соображений безопасности.   -  person koolunix    schedule 25.06.2014
comment
Я надеюсь, что нет, я бы предпочел позвонить, когда я знаю, что данные вернулись из API, но я не вижу, чтобы это работало даже через jQuery.   -  person Chris Southam    schedule 25.06.2014


Ответы (5)


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

<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();
                });
            });
        }
    }
})
person koolunix    schedule 25.06.2014
comment
Да! Вот именно - возможно я что-то не так делал, так как видел что-то похожее, но не использовал!! в теге HTML. Спасибо :) - person Chris Southam; 25.06.2014
comment
Почему setTimeout? Это потому, что этот цикл дайджеста еще не показывает элемент? $timeout легко справился бы с этим, не прибегая к произвольному времени. - person spenthil; 15.08.2014
comment
@spenhil- ты совершенно прав. Я обновил пример. Благодарю. - person koolunix; 20.08.2014
comment
Я не знаю, связано ли это с тем, что я использовал другую версию angular или что-то еще, но мне пришлось изменить $element.focus() на $element[0].focus() и то же самое для blur(), прежде чем это сработало. Кроме этого, это спасло день для меня. - person Corey Ogburn; 12.08.2015
comment
Вам также может понадобиться установить $element[0].select(), но самая большая проблема заключается в том, что он, скорее всего, не будет работать без указания задержки ожидания, поскольку и ng-hide, и ng-show появляются с определенной анимацией (ng-hide-animate), поэтому во время переходного периода вы можете невозможно установить фокус. В идеале вы должны получить период перехода от элемента, но я надеюсь, что указание некоторой фиксированной (50 мс) задержки также может сработать для вас. - person teamnorge; 20.12.2015

Я расширил ответ для работы с угловыми 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 />
person Neal Xiong    schedule 12.04.2015
comment
Это ТОЛЬКО то, что я искал, отличный код, который вы там сделали! Поздравляю! - person Luiz Eduardo; 14.07.2016
comment
Именно то, что я искал, это единственный ответ, который работает до сих пор - person robertjuh; 08.04.2017
comment
Это отлично работает в браузере, но на iPhone это не работает. - person Vikasdeep Singh; 09.03.2018

Основываясь на ответе 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();
                    });
                }
            );

        }
    };
});
person Chris Mc Cormick    schedule 17.02.2015

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

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

          }
        }
person user3092382    schedule 12.01.2018

Еще одна версия этого для 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 && !!changes.setFocus.currentValue) ?
      this.hostElement.nativeElement.focus() :
      this.hostElement.nativeElement.blur();
  }
}
person koolunix    schedule 24.07.2019