Pregunta Cómo obtener el elemento dom en angular 2 [duplicado]


Esta pregunta ya tiene una respuesta aquí:

Tengo un componente que tiene un p elemento. Sus onClick evento lo cambiará a textarea para que el usuario pueda editar los datos. Mi pregunta es:

  • ¿Cómo puedo enfocarme en el área de texto?
  • ¿Cómo puedo llegar al elemento para poder aplicar el .focus () en él?
  • ¿Puedo evitar el uso de document.getElemenntById ()?

He intentado usar "ElementRef" y "@ViewChild ()", pero parece que me falta algo:

// ------ 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>


76
2017-08-14 17:25


origen


Respuestas:


Utilizar ViewChild con #variable local como se muestra aquí,

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

</textarea>

En componente,

OLDEST Way

import {ElementRef} from '@angular/core';
@ViewChild('someVar') el:ElementRef;

ngAfterViewInit()
{
   this.el.nativeElement.focus();
}


Vieja forma

import {ElementRef} from '@angular/core';
@ViewChild('someVar') el:ElementRef;

constructor(private rd: Renderer) {}
ngAfterViewInit() {
    this.rd.invokeElementMethod(this.el.nativeElement,'focus');
}


Actualizado el 22/03 (marzo) / 2017

Nueva manera

Tenga en cuenta de Angular v4.0.0-rc.3 (2017-03-10) pocas cosas han sido cambiadas Dado que el equipo Angular desaprobará invokeElementMethod, el código anterior ya no se puede usar.

ROMPER CAMBIOS

desde 4.0 rc.1:

renombrar RendererV2 a Renderer2
  renombrar RendererTypeV2 a RendererType2
  renombrar RendererFactoryV2 a RendererFactory2

import {ElementRef,Renderer2} from '@angular/core';
@ViewChild('someVar') el:ElementRef;

constructor(private rd: Renderer2) {}

ngAfterViewInit() {
      console.log(this.rd); 
      this.el.nativeElement.focus();      //<<<=====same as oldest way
}

console.log(this.rd) le dará los siguientes métodos y puede ver ahora invokeElementMethod No está ahí. Adjuntar img aún no está documentado.

NOTA: Puede usar los siguientes métodos de Rendere2 con sin Variable ViewChild para hacer tantas cosas.

enter image description here


118
2017-08-14 17:46



Actualización (usando renderizador): 

Tenga en cuenta que el servicio de Renderer original ha quedado obsoleto en   favor de Renderer2

un hijo Renderer2 doc. Oficial

Además, como señala @ GünterZöchbauer:

En realidad, usar ElementRef está bien. También usando   ElementRef.nativeElement con Renderer2 está bien. Lo que se desalienta   está accediendo directamente a las propiedades de ElementRef.nativeElement.xxx.


Puedes lograr esto usando elementRef así como por ViewChild. sin embargo, no es recomendable usar elementRef debido a:

  • problema de seguridad
  • acoplamiento apretado

como se señala por documentación oficial ng2.

1. Usando elementRef (Acceso directo):

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

2. Usando ViewChild (mejor enfoque)

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

    }

40
2017-08-14 17:51



Angular 2.0.0 Final:

He encontrado que usando un ViewChild setter es la manera más confiable de establecer el foco de control de forma inicial:

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

El colocador primero se llama con un undefined valor seguido de una llamada con un inicializado ElementRef.

Ejemplo de trabajo y fuente completa aquí: http://plnkr.co/edit/u0sLLi?p=preview

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

ACTUALIZACIÓN para Angular 4+

Renderer ha sido desaprobado a favor de Renderer2, pero Renderer2  no tiene el invokeElementMethod. Necesitará acceder al DOM directamente para establecer el foco como en input.nativeElement.focus().

Todavía estoy encontrando que el ViewChild setter el enfoque funciona mejor Cuando usas AfterViewInit A veces me da read property 'nativeElement' of undefined error.

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

11
2017-09-24 17:45