web-dev-qa-db-fra.com

Comment obtenir un élément dom dans angular 2

J'ai un composant qui a un élément p. Son événement onClick le changera en textarea afin que l'utilisateur puisse modifier les données. Ma question est:

  • Comment puis-je faire le focus sur le textarea?
  • Comment puis-je atteindre l'élément pour pouvoir appliquer le .focus () dessus?
  • Puis-je éviter d'utiliser document.getElemenntById ()?

J'ai essayé d'utiliser "ElementRef" et "@ViewChild ()", mais il me semble qu'il manque quelque chose:

// ------ THE CLASS
@ViewChild('tasknoteId') taskNoteRef:ElementRef;

  noteEditMode: boolean = false;

 get isShowNote (){
    return  !this.noteEditMode && this.todo.note  ? true : false;
  }
  taskNote: string;
  toggleNoteEditMode () {
    this.noteEditMode = !this.noteEditMode;
      this.renderer.invokeElementMethod(this.taskNoteRef.nativeElement,'focus');
  }

// ------ THE COMPONENT
<span class="the-insert">
      <form [hidden]="!noteEditMode && todo.note">
        <textarea #tasknoteId id="tasknote"
                  name="tasknote"
                  [(ngModel)]="todo.note"
                  placeholder="{{ notePlaceholder }}"
                  style="background-color:pink"
                  (blur)="updateNote()" (click)="toggleNoteEditMode()"
                  [autofocus]="noteEditMode"
                  [innerHTML]="todo.note">
        </textarea>
      </form>
     </span>
121
Bastian

Mise à jour (à l'aide du moteur de rendu):

Notez que le service Renderer d'origine est maintenant obsolète en faveur de Renderer2.

comme sur doc officiel de Renderer2

En outre, comme l'a souligné @ GünterZöchbauer:

En fait, utiliser ElementRef est très bien. Également utiliser ElementRef.nativeElement avec Renderer2, c'est bien. Ce qui est déconseillé, c'est d'accéder directement aux propriétés de ElementRef.nativeElement.xxx.


Vous pouvez y parvenir en utilisant elementRef ainsi que par ViewChild. Cependant, il n'est pas recommandé d'utiliser elementRef pour les raisons suivantes:

  • problème de sécurité
  • couplage serré

comme indiqué par documentation officielle ng2 .

1. Utilisation de elementRef (accès direct):

export class MyComponent {    
constructor (private _elementRef : elementRef) {
 this._elementRef.nativeElement.querySelector('textarea').focus();
 }
}

2. En utilisant ViewChild ( meilleure approche ):

<textarea  #tasknote name="tasknote" [(ngModel)]="taskNote" placeholder="{{ notePlaceholder }}" 
style="background-color: pink" (blur)="updateNote() ; noteEditMode = false " (click)="noteEditMode = false"> {{ todo.note }} </textarea> // <-- changes id to local var


export class MyComponent implements AfterViewInit {
  @ViewChild('tasknote') input: ElementRef;

   ngAfterViewInit() {
    this.input.nativeElement.focus();

  }
}

3. Utiliser renderer:

export class MyComponent implements AfterViewInit {
      @ViewChild('tasknote') input: ElementRef;
         constructor(private renderer: Renderer2){           
          }

       ngAfterViewInit() {
       //using selectRootElement instead of depreaced invokeElementMethod
       this.renderer.selectRootElement(this.input["nativeElement"]).focus();
      }

    }
70
candidJ

Angular 2.0.0 Final:

J'ai constaté que l'utilisation d'un paramètre ViewChild est le moyen le plus fiable de définir le focus du contrôle de formulaire initial:

@ViewChild("myInput")
set myInput(_input: ElementRef | undefined) {
    if (_input !== undefined) {
        setTimeout(() => {
            this._renderer.invokeElementMethod(_input.nativeElement, "focus");
        }, 0);
    }
}

Le poseur est d'abord appelé avec une valeur undefined, suivie d'un appel avec un ElementRef initialisé.

Exemple de travail et source complète ici: http://plnkr.co/edit/u0sLLi?p=preview

Utilisation de TypeScript 2.0.3 Final/RTM, Angular 2.0.0 Final/RTM et Chrome 53.0.2785.116 m (64 bits).

UPDATE pour Angular 4 +

Renderer est déconseillé en faveur de Renderer2, mais Renderer2n'a pas la invokeElementMethod. Vous devrez accéder directement au DOM pour définir le focus comme dans input.nativeElement.focus().

Je constate toujours que l'approche de ViewChild setter fonctionne le mieux. Lors de l'utilisation de AfterViewInit j'obtiens parfois l'erreur read property 'nativeElement' of undefined.

@ViewChild("myInput")
set myInput(_input: ElementRef | undefined) {
    if (_input !== undefined) {
        setTimeout(() => { //This setTimeout call may not be necessary anymore.
            _input.nativeElement.focus();
        }, 0);
    }
}
10
KTCO