141 votes

Mettre le focus sur l'élément <input>

Je travaille sur une application frontale avec Angular 5, et j'ai besoin d'avoir une boîte de recherche cachée, mais sur le clic d'un bouton, la boîte de recherche doit être affichée et focalisée.

J'ai essayé quelques méthodes trouvées sur StackOverflow avec des directives ou autres, mais je n'y arrive pas.

Voici l'exemple de code :

@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();
  }

La boîte de recherche n'est pas configurée pour se focaliser.

Comment puis-je faire ça ?

164voto

Arvind Muthuraman Points 1185

Modifiez la méthode de recherche du spectacle comme suit

showSearch(){
  this.show = !this.show;  
  setTimeout(()=>{ // this will make the execution after the above boolean has changed
    this.searchElement.nativeElement.focus();
  },0);  
}

19 votes

Pourquoi avons-nous besoin d'utiliser setTimeout ? Le changement de booléen n'est-il pas synchrone ?

6 votes

Cela ne perturbe-t-il pas la zonejs ?

1 votes

@AndreiRosu, sans cela, j'obtenais une erreur car les modifications n'étaient pas rendues.

52voto

Nathaniel Points 105

Vous devez utiliser html autofocus pour ça :

<input *ngIf="show" #search type="text" autofocus /> 

Remarque : si votre composant est persistant et réutilisé, il ne sera autofocus que la première fois que le fragment sera attaché. Ceci peut être surmonté en ayant un écouteur dom global qui vérifie l'attribut autofocus à l'intérieur d'un fragment dom lorsqu'il est attaché et ensuite le réappliquer ou le focus via javascript.

65 votes

Cela ne fonctionnera qu'une fois par rafraîchissement de la page, et non plusieurs fois.

32voto

ggranum Points 91

Cette directive va instantanément mettre au point et sélectionner tout texte dans l'élément dès qu'il est affiché. Cela peut nécessiter un setTimeout dans certains cas, mais cela n'a pas été beaucoup testé.

import { Directive, ElementRef, OnInit } from '@angular/core';

@Directive({
  selector: '[appPrefixFocusAndSelect]',
})
export class FocusOnShowDirective implements OnInit {    
  constructor(private el: ElementRef) {
    if (!el.nativeElement['focus']) {
      throw new Error('Element does not accept focus.');
    }
  }

  ngOnInit(): void {
    const input: HTMLInputElement = this.el.nativeElement as HTMLInputElement;
    input.focus();
    input.select();
  }
}

Et dans le HTML :

<mat-form-field>
  <input matInput type="text" appPrefixFocusAndSelect [value]="'etc'">
</mat-form-field>

0 votes

Merci, c'est la seule solution qui a fonctionné pour moi dans le cas d'une attente sur une requête http.

2 votes

Je trouve cette solution plus préférable que la réponse acceptée. Elle est plus propre dans le cas de la réutilisation du code, et plus centrée sur Angular.

0 votes

N'oubliez pas non plus d'ajouter la directive dans les déclarations du module.

17voto

Je vais m'exprimer sur ce sujet (Solution Angular 7)

input [appFocus]="focus"....

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

2 votes

Cela semble être à peu près identique à la réponse acceptée

9voto

Marcin Restel Points 137

Pour que l'exécution se fasse après que le booléen ait changé et éviter l'utilisation du timeout, vous pouvez faire ce qui suit :

import { ChangeDetectorRef } from '@angular/core';

constructor(private cd: ChangeDetectorRef) {}

showSearch(){
  this.show = !this.show;  
  this.cd.detectChanges();
  this.searchElement.nativeElement.focus();
}

5 votes

J'ai essayé avec angular 7, mais cela n'a pas fonctionné. L'utilisation de timeout a bien fonctionné.

0 votes

Pour moi aussi dans angular 8 ne fonctionne pas, trop mauvais nous devons revenir à setTimeout

0 votes

Fonctionne très bien, au lieu de setTimeout en raison d'un rafraîchissement complet de la page par setTimeout affectant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X