- Cuando se abre un Modal, fije el foco en un <input> predefinido dentro de este Modal.
Defina una directiva y haga que $ vea una propiedad / disparador para que sepa cuándo enfocar el 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));
});
}
};
}]);
Saqueador
El tiempo de espera $ parece ser necesario para dar tiempo modal para renderizar.
'2.' Cada vez que <input> se hace visible (por ejemplo, haciendo clic en algún botón), establezca el foco en él.
Crea una directiva esencialmente como la de arriba. Observe algunas propiedades de alcance y, cuando se convierta en verdadero (configúrelo en su controlador ng-click), ejecute element[0].focus()
. Dependiendo de su caso de uso, puede necesitar o no un tiempo de espera 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;
//});
}
});
}
};
});
Saqueador
Actualización 7/2013 : he visto a algunas personas usar mis directivas de alcance de aislamiento originales y luego tienen problemas con los campos de entrada incrustados (es decir, un campo de entrada en el modal). Una directiva sin un nuevo alcance (o posiblemente un nuevo alcance infantil) debería aliviar algo del dolor. Así que arriba actualicé la respuesta para no usar ámbitos de aislamiento. A continuación se muestra la respuesta original:
Respuesta original para 1., usando un alcance aislado:
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 .
Respuesta original para 2., usando un alcance aislado:
<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 necesitamos restablecer la propiedad trigger / focusInput en la directiva, '=' se usa para el enlace de datos bidireccional. En la primera directiva, '@' era suficiente. También tenga en cuenta que cuando se usa '@', comparamos el valor de activación con "verdadero" ya que @ siempre da como resultado una cadena.
ng-model
en el campo de entrada, el valor del modelo se pierde cuando uso esta directiva con el alcance de aislamiento. El problema no ocurre si pruebo la versión de Josh sin el alcance de aislamiento. Todavía soy un novato, y me gustaría entender la diferencia. Aquí hay un Plunker que lo muestra.value != "true"
, y eso pareció solucionar mi problema.(EDITAR: he agregado una solución actualizada debajo de esta explicación)
Mark Rajcok es el hombre ... y su respuesta es una respuesta válida, pero
hatenido un defecto (lo siento Mark) ...... Intente usar el booleano para enfocar la entrada, luego desenfoque la entrada, luego intente usarla para enfocar la entrada nuevamente. No funcionará a menos que restablezca el valor booleano a falso, luego $ digest y luego lo restablezca a verdadero. Incluso si usa una comparación de cadenas en su expresión, se verá obligado a cambiar la cadena a otra cosa, $ digest, y luego volver a cambiarla.(Esto se ha solucionado con el controlador de eventos de desenfoque).Entonces propongo esta solución alternativa:
Use un evento, la característica olvidada de Angular.
JavaScript ama los eventos después de todo. Los eventos están intrínsecamente acoplados, y aún mejor, evitas agregar otro $ watch a tu $ digest.
Así que ahora puedes usarlo así:
y luego en cualquier parte de tu aplicación ...
Esto es increíble porque puedes hacer todo tipo de cosas con algo como esto. Por un lado, podría relacionarse con eventos que ya existen. Por otra parte, comienzas a hacer algo inteligente al hacer que diferentes partes de tu aplicación publiquen eventos a los que otras partes de tu aplicación pueden suscribirse.
De todos modos, este tipo de cosas me grita "evento impulsado". Creo que, como desarrolladores de Angular, nos esforzamos mucho por convertir las clavijas en forma de visor en agujeros de forma de evento.
¿Es la mejor solución? No se. Es una solucion.
Solución actualizada
Después del comentario de @ ShimonRachlenko a continuación, he cambiado ligeramente mi método de hacerlo. Ahora uso una combinación de un servicio y una directiva que maneja un evento "detrás de escena":
Aparte de eso, es el mismo director descrito anteriormente.
Aquí hay una demostración rápida de Plunk
Uso
Fuente
fuente
$broadcast
con$timeout
si desea que esto funcione al ingresar al controlador. De lo contrario, es una buena solución.He encontrado que algunas de las otras respuestas son demasiado complicadas cuando todo lo que realmente necesita es esto
el uso es
Usamos el tiempo de espera para dejar que las cosas en el dom se reproduzcan, aunque sea cero, al menos espera eso, de esa manera esto funciona en modales y otras cosas también
fuente
ng-click
: Digamos que hacer clic en un botón tieneng-click="showInput = !showInput
en su entrada. Luego, en su entrada real, agregueng-if="showInput"
. Al alternar el botón, la directiva se volverá a ejecutar cada vez. Estaba teniendo un problema con esto, ya que estaba usando,ng-show
que es el enfoque equivocado.HTML tiene un atributo
autofocus
.http://www.w3schools.com/tags/att_input_autofocus.asp
fuente
También puede usar la funcionalidad jqlite integrada en angular.
angular.element('.selector').trigger('focus');
fuente
Looking up elements via selectors is not supported by jqLite!
Esto funciona bien y es una forma angular de enfocar el control de entrada
Aunque esta no es una forma puramente angular de realizar la tarea, la sintaxis sigue un estilo angular. Jquery desempeña un papel indirecto y accede directamente al DOM usando Angular (jQLite => JQuery Light).
Si es necesario, este código se puede poner fácilmente dentro de una directiva angular simple donde el elemento es directamente accesible.
fuente
Looking up elements via selectors is not supported by jqLite!
angular.element
convierte en un contenedor para$() / jQuery()
. Entonces, sin eso, esto no funcionará, y básicamente estás usando jQuery de todos modos (peroNo creo que $ timeout sea una buena manera de enfocar el elemento en la creación. Aquí hay un método que utiliza la funcionalidad angular incorporada, extraída de las oscuras profundidades de los documentos angulares. Observe cómo el atributo "link" se puede dividir en "pre" y "post", para las funciones pre-link y post-link.
Ejemplo de trabajo: http://plnkr.co/edit/Fj59GB
Documentos completos de la Directiva AngularJS: https://docs.angularjs.org/api/ng/service/$compile
fuente
Aquí está mi solución original:
saqueador
Y el HTML:
Que hace:
Enfoca la entrada a medida que se hace visible con ng-show. No hay uso de $ watch o $ aquí.
fuente
He escrito una directiva de enfoque vinculante bidireccional, al igual que el modelo recientemente.
Puede usar la directiva de enfoque de esta manera:
Si realiza alguna variable de alcance VariableFocus
true
en cualquier parte de su controlador, la entrada se enfocará. Y si desea "desenfocar" su entrada, someFocusVariable se puede establecer en falso. Es como la primera respuesta de Mark Rajcok pero con enlace bidireccional.Aquí está la directiva:
Uso:
Aquí está el violín:
http://fiddle.jshell.net/ubenzer/9FSL4/8/
fuente
Para aquellos que usan Angular con el complemento Bootstrap:
http://angular-ui.github.io/bootstrap/#/modal
Puede engancharse a la
opened
promesa de la instancia modal:fuente
$timeout
con50ms
es necesario en lugar de0
.Me pareció útil usar una expresión general. De esta manera, puede hacer cosas como mover automáticamente el foco cuando el texto de entrada es válido
O enfocar automáticamente cuando el usuario completa un campo de longitud fija
Y, por supuesto, enfocarse después de la carga
El código de la directiva:
fuente
No para resucitar a un zombie o conectar mi propia directiva (ok, eso es exactamente lo que estoy haciendo):
https://github.com/hiebj/ng-focus-if
http://plnkr.co/edit/MJS3zRk079Mu72o5A9l6?p=preview
fuente
Primero, una forma oficial de enfocarse es en la hoja de ruta para 1.1 . Mientras tanto, puede escribir una directiva para implementar el enfoque de configuración.
En segundo lugar, establecer el foco en un elemento después de que se haya vuelto visible actualmente requiere una solución alternativa. Simplemente retrase su llamada al elemento focus () con a
$timeout
.Debido a que existe el mismo problema controlador-modifica-DOM para el enfoque, desenfoque y selección, propongo tener una
ng-target
directiva:Hilo angular aquí: http://goo.gl/ipsx4 , y más detalles publicados aquí: http://goo.gl/4rdZa
La siguiente directiva creará una
.focus()
función dentro de su controlador según lo especificado por sung-target
atributo. (Crea una.blur()
y una.select()
también.) Demostración: http://jsfiddle.net/bseib/WUcQX/fuente
ngFocus
parece ser una forma de manejarfocus
los eventos, no una forma de establecer el foco en un elemento.En lugar de crear su propia directiva, es posible simplemente usar las funciones de JavaScript para lograr un enfoque.
Aquí hay un ejemplo.
En el archivo html:
En un archivo javascript, en un controlador, por ejemplo, donde desea activar el foco:
fuente
Si solo deseaba un enfoque simple que fuera controlado por un clic ng.
HTML:
Directiva:
fuente
Una simple que funciona bien con modales:
Ejemplo
fuente
Simplemente podría crear una directiva que obligue a centrarse en el elemento decorado en postLinking:
Luego en tu html:
Esto funcionaría para modals y ng-if elementos alternados, no para ng-show ya que postLinking ocurre solo en el procesamiento HTML.
fuente
Mark y Blesh tienen excelentes respuestas; sin embargo, Mark's tiene una falla que señala Blesh (además de ser compleja de implementar), y siento que la respuesta de Blesh tiene un error semántico al crear un servicio que se trata específicamente de enviar una solicitud de enfoque a la interfaz cuando realmente todo lo que necesitaba era una forma de retrasar el evento hasta que todas las directivas estuvieran escuchando.
Así que esto es lo que terminé haciendo, que roba mucho de la respuesta de Blesh, pero mantiene la semántica del evento del controlador y el servicio "después de la carga" por separado.
Esto permite que el evento del controlador se enganche fácilmente para otras cosas que no sean solo enfocar un elemento específico y también permite incurrir en la sobrecarga de la funcionalidad "después de la carga" solo si es necesario, lo que puede no serlo en muchos casos.
Uso
Fuente
fuente
Esto también es posible de usar
ngModelController
. Trabajando con 1.6+ (no lo sé con versiones anteriores).HTML
JS
-
NB: Dependiendo del contexto, es posible que deba ajustar una función de tiempo de espera.
NB²: cuando se usa
controllerAs
, esto es casi lo mismo. Basta con sustituirname="myForm"
conname="vm.myForm"
y en JS,vm.myForm.myText.$$element.focus();
.fuente
Probablemente, la solución más simple en la era ES6.
Agregar la siguiente directiva de línea hace que el atributo HTML 'autofocus' sea efectivo en Angular.js.
Ahora, puede usar la sintaxis de enfoque automático HTML5 como:
fuente
.directive('autofocus', ['$timeout', ($timeout) => ({link: (_, e) => $timeout(() => e[0].focus())})])
Solo soy un novato aquí, pero pude hacerlo funcionar en un ui.bootstrap.modal con esta directiva:
y en el método $ modal.open utilicé lo siguiente para indicar el elemento donde se debe poner el foco:
en la plantilla tengo esto:
fuente
La siguiente directiva me sirvió. Utilice el mismo atributo html de enfoque automático para la entrada.
fuente
Si está usando modalInstance y tiene el objeto, puede usar "entonces" para realizar acciones después de abrir el modal. Si no está usando modalInstance y está codificado para abrir el modal, puede usar el evento. El $ timeout no es una buena solución.
Puedes hacer (Bootstrap3):
En modalInstance puede mirar la biblioteca para ver cómo ejecutar el código después de abrir modal.
No use $ timeout de esta manera, el $ timeout puede ser 0, 1, 10, 30, 50, 200 o más, esto dependerá de la computadora del cliente y del proceso para abrir modal.
No uses $ timeout, deja que el método te diga cuándo puedes concentrarte;)
Espero que esto ayude! :)
fuente
Toda la respuesta anterior no funciona si el elemento de enfoque deseado se inyecta en una plantilla directiva. La siguiente directiva se ajusta tanto al elemento simple como al elemento inyectado por la directiva (lo escribí en mecanografiado ). acepta selector para elemento enfocable interno. si solo necesita enfocar el elemento self, no envíe ningún parámetro selector a la directiva:
}
ejemplo de uso para elemento simple:
ejemplo de uso para el elemento interno (generalmente para el elemento inyectado dinámico como la directiva con plantilla):
puede usar cualquier selector jQuery en lugar de "input"
fuente
Edito la directiva focusMe de Mark Rajcok para trabajar para el enfoque múltiple en un elemento.
HTML:
en el controlador AngularJs:
Directiva AngulaJS:
fuente
Quiero contribuir a esta discusión después de buscar una mejor solución y no encontrarla, teniendo que crearla en su lugar.
Criterios: 1. La solución debe ser independiente del alcance del controlador principal para aumentar la reutilización. 2. Evite el uso de $ watch para monitorear alguna condición, esto es lento, aumenta el tamaño del bucle de digestión y dificulta las pruebas. 3. Evite $ timeout o $ scope. $ Apply () para activar un bucle de resumen. 4. Un elemento de entrada está presente dentro del elemento donde se utiliza la Directiva abierta.
Esta es la solución que más me gustó:
Directiva:
HTML:
¡Espero que esto ayude a alguien por ahí!
fuente
Es fácil ... prueba esto
html
javascript
fuente
Si desea establecer el foco en un elemento en particular, puede usar el siguiente enfoque.
Crea un servicio llamado
focus
.Inyecte en el controlador desde donde desea llamar.
Llama a este servicio.
fuente
Creo que la directiva es innecesaria. Use la identificación HTML y los atributos de clase para seleccionar el elemento requerido y haga que el servicio use document.getElementById o document.querySelector para aplicar el foco (o equivalentes jQuery).
El marcado es directivas HTML / angulares estándar con id / clases agregadas para la selección
Controlador difunde evento
En la interfaz de usuario, el servicio utiliza querySelector: si hay varias coincidencias (por ejemplo, debido a la clase), solo devolverá la primera
Es posible que desee usar $ timeout () para forzar un ciclo de resumen
fuente
Solo tirando un poco de café.
fuente