- Quando um Modal é aberto, defina o foco em uma <entrada> predefinida dentro deste Modal.
Defina uma diretiva e faça com que $ watch uma propriedade / gatilho saiba para quando focar o elemento:
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's comment, set attribute value to 'false'
// on blur event:
element.bind('blur', function () {
console.log('blur');
scope.$apply(model.assign(scope, false));
});
}
};
}]);
Plunker
O $ timeout parece ser necessário para fornecer o tempo modal para renderização.
'2.' Sempre que <entrada> ficar visível (por exemplo, clicando em algum botão), defina o foco.
Crie uma diretiva essencialmente como a acima. Observe alguma propriedade do escopo e, quando ela se tornar verdadeira (configure-a no manipulador de ng-click), execute element[0].focus()
. Dependendo do seu caso de uso, você pode ou não precisar de um tempo limite de $ para este:
<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
Atualização 7/2013 : vi algumas pessoas usarem minhas diretivas originais de escopo isolado e, em seguida, ter problemas com campos de entrada incorporados (ou seja, um campo de entrada no modal). Uma diretiva sem novo escopo (ou possivelmente um novo escopo filho) deve aliviar parte da dor. Portanto, atualizei a resposta para não usar escopos isolados. Abaixo está a resposta original:
Resposta original para 1., usando um escopo isolado:
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 .
Resposta original para 2., usando um escopo isolado:
<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 .
Como precisamos redefinir a propriedade trigger / focusInput na diretiva, '=' é usado para a ligação de dados bidirecional. Na primeira diretiva, '@' era suficiente. Observe também que, ao usar '@', comparamos o valor do acionador como "true", pois @ sempre resulta em uma string.
ng-model
no campo de entrada, o valor do modelo será perdido quando eu usar esta diretiva com o escopo isolado. O problema não acontece se eu tentar a versão de Josh sem o escopo isolado. Ainda sou novato e gostaria de entender a diferença. Aqui está um Plunker que mostra isso.value != "true"
, e isso pareceu resolver o meu problema.(EDIT: eu adicionei uma solução atualizada abaixo desta explicação)
Mark Rajcok é o homem ... e sua resposta é uma resposta válida, mas
temtido um defeito (desculpe Mark) ...... Tente usar o booleano para focar a entrada, depois desfoque a entrada e tente usá-lo para focar a entrada novamente. Não funcionará, a menos que você redefina o booleano para false e, em seguida, $ digest, em seguida, redefina-o para true. Mesmo se você usar uma comparação de cadeias na sua expressão, será forçado a alterar a cadeia para outra coisa, $ digest, e depois alterá-la novamente.(Isso foi resolvido com o manipulador de eventos de desfoque.)Então, proponho esta solução alternativa:
Use um evento, o recurso esquecido do Angular.
Afinal, o JavaScript adora eventos. Os eventos são inerentemente fracamente acoplados e, melhor ainda, você evita adicionar outro $ watch ao seu $ digest.
Então agora você pode usá-lo assim:
e depois em qualquer lugar do seu aplicativo ...
Isso é incrível, porque você pode fazer todo tipo de coisa com algo assim. Por um lado, você pode se associar a eventos que já existem. Por outro lado, você começa a fazer algo inteligente, fazendo com que diferentes partes do seu aplicativo publiquem eventos nos quais outras partes do seu aplicativo possam se inscrever.
De qualquer forma, esse tipo de coisa grita "dirigido a eventos" para mim. Acho que, como desenvolvedores Angular, tentamos arduamente martelar pinos em forma de escopo $ em buracos em forma de evento.
É a melhor solução? Não sei. É uma solução.
Solução atualizada
Após o comentário de @ ShimonRachlenko abaixo, mudei meu método de fazer isso um pouco. Agora eu uso uma combinação de um serviço e uma diretiva que lida com um evento "nos bastidores":
Fora isso, é o mesmo princípio descrito acima.
Aqui está uma rápida demonstração Plunk
Uso
Fonte
fonte
$broadcast
com$timeout
se quiser que isso funcione ao entrar no controlador. Caso contrário, boa solução.Eu achei algumas das outras respostas muito complicadas quando tudo o que você realmente precisa é isso
uso é
Usamos o tempo limite para deixar as coisas no dom renderizarem, mesmo que seja zero, pelo menos espera por isso - dessa forma, isso funciona em modais e outros enfeites também.
fonte
ng-click
: digamos que clicar em um botão tenhang-click="showInput = !showInput
sua entrada. Em seguida, na sua entrada real, adicioneng-if="showInput"
. Se você pressionar o botão, a diretiva será executada novamente a cada vez. Eu estava tendo um problema com isso, pois estava usandong-show
a abordagem errada.HTML tem um atributo
autofocus
.http://www.w3schools.com/tags/att_input_autofocus.asp
fonte
Você também pode usar a funcionalidade jqlite incorporada ao angular.
angular.element('.selector').trigger('focus');
fonte
Looking up elements via selectors is not supported by jqLite!
Isso funciona bem e uma maneira angular de focar o controle de entrada
Embora essa não seja uma maneira angular pura de executar a tarefa, a sintaxe segue o estilo angular. O Jquery desempenha um papel indiretamente e acessa diretamente o DOM usando Angular (jQLite => JQuery Light).
Se necessário, esse código pode ser facilmente inserido em uma diretiva angular simples, na qual o elemento é diretamente acessível.
fonte
Looking up elements via selectors is not supported by jqLite!
angular.element
se torna um invólucro$() / jQuery()
. Assim, sem que isto não vai funcionar, e você está basicamente apenas usando jQuery qualquer maneira (mas me corrija se eu estiver errado)Não acho que $ timeout seja uma boa maneira de focar o elemento na criação. Aqui está um método usando a funcionalidade angular interna, extraída das profundezas obscuras dos documentos angulares. Observe como o atributo "link" pode ser dividido em "pré" e "post", para funções de pré-link e pós-link.
Exemplo de trabalho: http://plnkr.co/edit/Fj59GB
Documentos da Diretiva AngularJS completa: https://docs.angularjs.org/api/ng/service/$compile
fonte
Aqui está a minha solução original:
plunker
E o HTML:
O que faz:
Ele focaliza a entrada à medida que se torna visível com o ng-show. Não é possível usar $ watch ou $ aqui.
fonte
Eu escrevi uma diretiva de foco de ligação bidirecional, assim como o modelo recentemente.
Você pode usar a diretiva focus como esta:
Se você criar alguma variável de escopoFocusVariable
true
em qualquer lugar do seu controlador, a entrada será focada. E se você deseja "desfocar" sua entrada, é possível definir alguma variável de foco como false. É como a primeira resposta de Mark Rajcok, mas com ligação de mão dupla.Aqui está a diretiva:
Uso:
Aqui está o violino:
http://fiddle.jshell.net/ubenzer/9FSL4/8/
fonte
Para quem usa Angular com o plug-in Bootstrap:
http://angular-ui.github.io/bootstrap/#/modal
Você pode se conectar à
opened
promessa da instância modal:fonte
$timeout
com50ms
está em necessidade, em vez de0
.Achei útil usar uma expressão geral. Dessa forma, você pode fazer coisas como mover automaticamente o foco quando o texto de entrada é válido
Ou focalize automaticamente quando o usuário preencher um campo de comprimento fixo
E, claro, foco após carregamento
O código da diretiva:
fonte
Para não ressuscitar um zumbi ou conectar minha própria diretiva (ok, é exatamente isso que estou fazendo):
https://github.com/hiebj/ng-focus-if
http://plnkr.co/edit/MJS3zRk079Mu72o5A9l6?p=preview
fonte
Primeiro, uma maneira oficial de focar é no roteiro para 1.1 . Enquanto isso, você pode escrever uma diretiva para implementar o foco da configuração.
Segundo, para definir o foco em um item depois que ele se tornou visível atualmente, é necessária uma solução alternativa. Apenas adie sua chamada para o elemento focus () com a
$timeout
.Como o mesmo problema de controlador-modifica-DOM existe para foco, desfoque e seleção, proponho ter uma
ng-target
diretiva:Segmento angular aqui: http://goo.gl/ipsx4 e mais detalhes publicados em blog aqui: http://goo.gl/4rdZa
A diretiva a seguir criará uma
.focus()
função dentro do seu controlador, conforme especificado pelo seung-target
atributo. (Ele cria um.blur()
e um.select()
também.) Demo: http://jsfiddle.net/bseib/WUcQX/fonte
ngFocus
parece ser uma maneira de lidar comfocus
eventos, não uma maneira de definir o foco em um elemento.Em vez de criar sua própria diretiva, é possível simplesmente usar funções javascript para obter um foco.
Aqui está um exemplo.
No arquivo html:
Em um arquivo javascript, em um controlador, por exemplo, onde você deseja ativar o foco:
fonte
Se você queria apenas um foco simples, controlado por um clique-ng.
Html:
Directiva:
fonte
Simples que funciona bem com os modais:
Exemplo
fonte
Você pode apenas criar uma diretiva que force o foco no elemento decorado no postLinking:
Então, no seu html:
Isso funcionaria para elementos modais e ng-se alternados, não para ng-show, pois o postLinking acontece apenas no processamento HTML.
fonte
Mark e Blesh têm ótimas respostas; no entanto, Mark tem uma falha que Blesh aponta (além de ser complexa de implementar), e eu sinto que a resposta de Blesh tem um erro semântico na criação de um serviço que é especificamente sobre o envio de solicitação de foco para o front-end quando realmente tudo o que ele precisava era uma maneira de adie o evento até que todas as diretivas estejam ouvindo.
Então, eis o que acabei fazendo, que rouba muito a resposta de Blesh, mas mantém a semântica do evento do controlador e o serviço "pós-carregamento" separados.
Isso permite que o evento do controlador seja facilmente conectado a outras coisas que não sejam apenas o foco em um elemento específico e também permite incorrer na sobrecarga da funcionalidade "pós-carregamento" apenas se for necessário, o que pode não acontecer em muitos casos.
Uso
Fonte
fonte
Isso também é possível de usar
ngModelController
. Trabalhando com 1.6+ (não sei com versões mais antigas).HTML
JS
-
NB: Dependendo do contexto, talvez você precise quebrar uma função de tempo limite.
NB²: Ao usar
controllerAs
, isso é quase o mesmo. Apenas substituaname="myForm"
porname="vm.myForm"
e em JSvm.myForm.myText.$$element.focus();
,.fonte
Provavelmente, a solução mais simples para a idade do ES6.
A adição da seguinte diretiva de liner torna o atributo 'autofoco' do HTML eficaz no Angular.js.
Agora, você pode usar a sintaxe de foco automático HTML5 como:
fonte
.directive('autofocus', ['$timeout', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())})])
Apenas um novato aqui, mas eu era capaz de fazê-lo funcionar em um ui.bootstrap.modal com esta diretiva:
e no método $ modal.open, usei o seguinte para indicar o elemento em que o foco deve ser colocado:
no modelo eu tenho isso:
fonte
A diretiva a seguir fez o truque para mim. Use o mesmo atributo html de foco automático para entrada.
fonte
Se você estiver usando modalInstance e tiver o objeto, poderá usar "then" para executar ações após abrir o modal. Se você não estiver usando o modalInstance e for codificado para abrir o modal, poderá usar o evento. O tempo limite de $ não é uma boa solução.
Você pode fazer (Bootstrap3):
Em modalInstance, você pode ver na biblioteca como executar o código após o modal aberto.
Não use $ timeout assim, o $ timeout pode ser 0, 1, 10, 30, 50, 200 ou mais, isso dependerá do computador cliente e do processo de abertura modal.
Não use $ timeout, deixe o método informar quando você pode se concentrar;)
Espero que isso ajude! :)
fonte
Toda a resposta anterior não funciona se o elemento de foco desejado for injetado em um modelo de diretiva. A diretiva a seguir se encaixa no elemento simples ou no elemento injetado de diretiva (escrevi em texto datilografado ). aceita seletor para o elemento focalizável interno. se você só precisa focar o elemento self - não envie nenhum parâmetro seletor para a diretiva:
}
exemplo de uso para elemento simples:
exemplo de uso para elemento interno (geralmente para elemento injetado dinâmico como diretiva com modelo):
você pode usar qualquer seletor jQuery em vez de "input"
fonte
Eu edito a diretiva focusMe de Mark Rajcok para trabalhar com foco múltiplo em um elemento.
HTML:
no AngularJs Controller:
Diretiva AngulaJS:
fonte
Quero contribuir para esta discussão depois de procurar uma solução melhor e não encontrá-la, tendo que criá-la.
Critérios: 1. A solução deve ser independente do escopo do controlador pai para aumentar a reutilização. 2. Evite o uso de $ watch para monitorar alguma condição, isso é lento, aumenta o tamanho do loop digest e dificulta o teste. 3. Evite $ timeout ou $ scope. $ Apply () para acionar um loop de digestão. 4. Um elemento de entrada está presente no elemento em que a diretiva é usada em aberto.
Esta é a solução que eu mais gostei:
Directiva:
Html:
Espero que isso ajude alguém por aí!
fonte
É fácil .. tente isso
html
javascript
fonte
Se você deseja focar em um elemento específico, pode usar a abordagem abaixo.
Crie um serviço chamado
focus
.Injete-o no controlador de onde você deseja ligar.
Ligue para este serviço.
fonte
Penso que a directiva é desnecessária. Use os atributos de ID e classe HTML para selecionar o elemento necessário e faça com que o serviço use document.getElementById ou document.querySelector para aplicar o foco (ou equivalentes a jQuery).
A marcação é diretivas HTML / angulares padrão com ID / classes adicionadas para seleção
Evento de transmissões do controlador
Na interface do usuário, o serviço usa querySelector - se houver várias correspondências (por exemplo, devido à classe), ele retornará apenas a primeira
Você pode usar $ timeout () para forçar um ciclo de resumo
fonte
Apenas jogando um pouco de café.
fonte