Definir o foco do elemento de maneira angular

Depois de procurar exemplos de como definir elementos de foco com angular, vi que a maioria deles usa alguma variável para observar e, em seguida, definir o foco, e a maioria usa uma variável diferente para cada campo que deseja definir o foco. De uma forma, com muitos campos, isso implica em muitas variables ​​diferentes.

Com o jquery em mente, mas querendo fazer isso de forma angular, eu fiz uma solução que definimos o foco em qualquer function usando o id do elemento, então, como sou muito novo em angular, gostaria de obter algumas opiniões se Dessa forma é certo, tem problemas, tudo o que possa me ajudar a fazer o melhor caminho em angular.

Basicamente, eu crio uma diretiva que observa um valor de escopo definido pelo usuário com a diretiva, ou o focusElement do padrão, e quando esse valor é o mesmo que o id do elemento, esse elemento define o próprio foco.

angular.module('appnamehere') .directive('myFocus', function () { return { restrict: 'A', link: function postLink(scope, element, attrs) { if (attrs.myFocus == "") { attrs.myFocus = "focusElement"; } scope.$watch(attrs.myFocus, function(value) { if(value == attrs.id) { element[0].focus(); } }); element.on("blur", function() { scope[attrs.myFocus] = ""; scope.$apply(); }) } }; }); 

Uma input que precisa obter foco por algum motivo, fará isso

  

Aqui qualquer elemento para definir o foco:

 Set focus 

E a function de exemplo que define o foco:

 $scope.clickButton = function() { $scope.focusElement = "input1"; } 

Isso é uma boa solução em angular? Tem problemas que com a minha má experiência ainda não vejo?

O problema com a sua solução é que ela não funciona bem quando ligada a outras diretivas que criam um novo escopo, por exemplo, ng-repeat . Uma solução melhor seria simplesmente criar uma function de serviço que permita focar elementos imperativamente dentro de seus controladores ou focar elementos declarativamente no html.

DEMO

JAVASCRIPT

Serviço

  .factory('focus', function($timeout, $window) { return function(id) { // timeout makes sure that it is invoked after any other event has been triggered. // eg click events that need to run before the focus or // inputs elements that are in a disabled state but are enabled when those events // are triggered. $timeout(function() { var element = $window.document.getElementById(id); if(element) element.focus(); }); }; }); 

Directiva

  .directive('eventFocus', function(focus) { return function(scope, elem, attr) { elem.on(attr.eventFocus, function() { focus(attr.eventFocusId); }); // Removes bound events in the element itself // when the scope is destroyed scope.$on('$destroy', function() { elem.off(attr.eventFocus); }); }; }); 

Controlador

 .controller('Ctrl', function($scope, focus) { $scope.doSomething = function() { // do something awesome focus('email'); }; }); 

HTML

    

Sobre essa solução, poderíamos apenas criar uma diretiva e anexá-la ao elemento DOM que precisa obter o foco quando uma determinada condição for satisfeita. Seguindo esta abordagem, evitamos o acoplamento do controlador aos IDs dos elementos DOM.

Diretiva de código de amostra:

 gbndirectives.directive('focusOnCondition', ['$timeout', function ($timeout) { var checkDirectivePrerequisites = function (attrs) { if (!attrs.focusOnCondition && attrs.focusOnCondition != "") { throw "FocusOnCondition missing attribute to evaluate"; } } return { restrict: "A", link: function (scope, element, attrs, ctrls) { checkDirectivePrerequisites(attrs); scope.$watch(attrs.focusOnCondition, function (currentValue, lastValue) { if(currentValue == true) { $timeout(function () { element.focus(); }); } }); } }; } ]); 

Um uso possível

 .controller('Ctrl', function($scope) { $scope.myCondition = false; // you can just add this to a radiobutton click value // or just watch for a value to change... $scope.doSomething = function(newMyConditionValue) { // do something awesome $scope.myCondition = newMyConditionValue; }; 

});

HTML

  

Eu gosto de evitar pesquisas de DOM, relógios e emissores globais sempre que possível, então eu uso uma abordagem mais direta. Use uma diretiva para atribuir uma function simples que enfoca o elemento diretivo. Em seguida, chame essa function sempre que necessário dentro do escopo do controlador.

Aqui está uma abordagem simplificada para anexá-lo ao escopo. Veja o trecho completo para manipular a syntax controller-as.

Directiva:

 app.directive('inputFocusFunction', function () { 'use strict'; return { restrict: 'A', link: function (scope, element, attr) { scope[attr.inputFocusFunction] = function () { element[0].focus(); }; } }; }); 

e em html:

   

ou no controlador:

 $scope.focusOnSaveInput(); 
 angular.module('app', []) .directive('inputFocusFunction', function() { 'use strict'; return { restrict: 'A', link: function(scope, element, attr) { // Parse the attribute to accomodate assignment to an object var parseObj = attr.inputFocusFunction.split('.'); var attachTo = scope; for (var i = 0; i < parseObj.length - 1; i++) { attachTo = attachTo[parseObj[i]]; } // assign it to a function that focuses on the decorated element attachTo[parseObj[parseObj.length - 1]] = function() { element[0].focus(); }; } }; }) .controller('main', function() {}); 
      

Podes tentar

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

por exemplo.

 angular.element('#txtUserId').focus(); 

está funcionando para mim.

Outra opção seria usar a arquitetura pub-sub integrada do Angular para notificar sua diretiva a se concentrar. Semelhante às outras abordagens, mas não está diretamente vinculado a uma propriedade e, em vez disso, está escutando seu escopo para uma chave específica.

Directiva:

 angular.module("app").directive("focusOn", function($timeout) { return { restrict: "A", link: function(scope, element, attrs) { scope.$on(attrs.focusOn, function(e) { $timeout((function() { element[0].focus(); }), 10); }); } }; }); 

HTML:

  

Controlador:

 //Assume this is within your controller //And you've hit the point where you want to focus the input: $scope.$broadcast("focusTextInput"); 

Eu preferi usar uma expressão. Isso me permite fazer coisas como focar em um botão quando um campo é válido, atingir um certo tamanho e, claro, após o carregamento.

  

Em uma forma complexa, isso também reduz a necessidade de criar variables ​​de escopo adicionais para fins de foco.

Veja https://stackoverflow.com/a/29963695/937997