Estoy trabajando en una aplicación front-end con Angular 5, y necesito tener un cuadro de búsqueda oculto, pero al hacer clic en un botón, el cuadro de búsqueda debería mostrarse y enfocarse.
He intentado algunas formas encontradas en StackOverflow con directiva o algo así, pero no puedo tener éxito.
Aquí está el código de ejemplo:
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello</h2>
</div>
<button (click) ="showSearch()">Show Search</button>
<p></p>
<form>
<div >
<input *ngIf="show" #search type="text" />
</div>
</form>
`,
})
export class App implements AfterViewInit {
@ViewChild('search') searchElement: ElementRef;
show: false;
name:string;
constructor() {
}
showSearch(){
this.show = !this.show;
this.searchElement.nativeElement.focus();
alert("focus");
}
ngAfterViewInit() {
this.firstNameElement.nativeElement.focus();
}
El cuadro de búsqueda no está configurado para enfocar.
¿Cómo puedo hacer eso?
setTimeout(() => { this.searchElement.nativeElement.focus() }, 100)
Debe usar el enfoque automático html para esto:
Nota: si su componente se conserva y se reutiliza, solo se enfocará automáticamente la primera vez que se adjunte el fragmento. Esto se puede superar teniendo un oyente de dom global que verifique el atributo de enfoque automático dentro de un fragmento de dom cuando se adjunta y luego lo vuelva a aplicar o se enfoque a través de javascript.
fuente
Esta directiva enfocará y seleccionará instantáneamente cualquier texto en el elemento tan pronto como se muestre. Esto puede requerir un setTimeout para algunos casos, no se ha probado mucho.
Y en el HTML:
fuente
Voy a opinar sobre esto (Solución Angular 7)
import {AfterViewInit, Directive, ElementRef, Input,} from '@angular/core'; @Directive({ selector: 'input[appFocus]', }) export class FocusDirective implements AfterViewInit { @Input('appFocus') private focused: boolean = false; constructor(public element: ElementRef<HTMLElement>) { } ngAfterViewInit(): void { // ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. if (this.focused) { setTimeout(() => this.element.nativeElement.focus(), 0); } } }
fuente
Esto está funcionando en Angular 8 sin setTimeout:
Explicación: Ok, esto funciona debido a: Detección de cambios. Es la misma razón por la que setTimout funciona, pero cuando se ejecuta un setTimeout en Angular, omitirá Zone.js y ejecutará todas las comprobaciones nuevamente, y funciona porque cuando setTimeout se completa, todos los cambios se completan. Con el gancho de ciclo de vida correcto (AfterContentChecked) se puede alcanzar el mismo resultado, pero con la ventaja de que no se ejecutará el ciclo adicional. La función se activará cuando se verifiquen y pasen todos los cambios, y se ejecutará después de los ganchos AfterContentInit y DoCheck. Si me equivoco aquí, corrígeme.
Más ciclos de vida y detección de cambios en https://angular.io/guide/lifecycle-hooks
ACTUALIZACIÓN : encontré una forma aún mejor de hacer esto si uno está usando Angular Material CDK, el paquete a11y. Primero importe A11yModule en el módulo que declara el componente en el que tiene el campo de entrada. Luego use las directivas cdkTrapFocus y cdkTrapFocusAutoCapture y use así en html y establezca tabIndex en la entrada:
Tuvimos algunos problemas con nuestros menús desplegables con respecto al posicionamiento y la capacidad de respuesta y comenzamos a usar OverlayModule desde el cdk, y este método que usa A11yModule funciona perfectamente.
fuente
cdkTrapFocusAutoCapture
atributo, pero cambié tu primer ejemplo en mi código. Por razones desconocidas (para mí), no funcionó con el gancho del ciclo de vida AfterContentChecked, sino solo con OnInit. En particular con AfterContentChecked, no puedo cambiar el enfoque y moverme (con el mouse o el teclado) a otra entrada sin esa directiva en la misma forma.Para realizar la ejecución después de que el booleano haya cambiado y evitar el uso del tiempo de espera, puede hacer lo siguiente:
fuente
En Angular, dentro del propio HTML, puede establecer el enfoque para ingresar al hacer clic en un botón.
fuente
mat-select
selectionChanged
evento que ocurre antes que otras cosas de la interfaz de usuario, por lo que enfocar el foco en ese punto no funcionó. En lugar de eso tenía que escribir un métodosetFocus(el:HTMLElement):void { setTimeout(()=>el.focus(),0); }
y llamarlo desde el controlador de eventos:<mat-select (selectionChanged)="setFocus(myInput)">
. No es tan agradable, pero simple y funciona bien. ¡gracias!También hay un atributo DOM llamado
cdkFocusInitial
que funciona para mí en las entradas. Puede leer más sobre esto aquí: https://material.angular.io/cdk/a11y/overviewfuente
Solo usando plantilla angular
fuente
html del componente:
<input [cdkTrapFocusAutoCapture]="show" [cdkTrapFocus]="show">
controlador de componente:
showSearch() { this.show = !this.show; }
..y no te olvides de importar A11yModule desde @ angular / cdk / a11y
import { A11yModule } from '@angular/cdk/a11y'
fuente
Una forma más fácil también es hacer esto.
fuente