Как получить элемент dom в angular 2

У меня есть компонент, который имеет элемент p. Его событие onClick изменит его на textarea, чтобы пользователь мог редактировать данные. Мой вопрос:

  • Как я могу сосредоточиться на текстовом поле?
  • Как я могу достичь элемента, чтобы я мог использовать .focus() на нем?
  • Можно ли использовать document.getElemenntById()?

Я попытался использовать "ElementRef" и "@ViewChild()", однако кажется, что я что-то пропустил:

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

Ответ 1

Используйте ViewChild с #localvariable, как показано здесь,

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

</textarea>

В компоненте

OLDEST Way

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

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


OLD Way

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

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


Обновлено 22/03 (март)/2017

НОВЫЙ способ

Обратите внимание, что с Angular v4.0.0-rc.3 (2017-03-10) было изменено несколько вещей. Поскольку команда Angular будет осуждать invokeElementMethod, код выше не может использоваться.

РАЗРЕШЕНИЕ ИЗМЕНЕНИЙ

так как 4.0 rc.1:

переименовать RendererV2 в Renderer2
переименовать RendererTypeV2 в RendererType2
переименуйте RendererFactoryV2 в 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) предоставит вам следующие методы, и теперь вы можете видеть invokeElementMethod. Прикрепление img пока не задокументировано.

ПРИМЕЧАНИЕ. Вы можете использовать следующие методы Rendere2 с/без переменной ViewChild, чтобы сделать так много вещей.

введите описание изображения здесь

Ответ 2

Обновление (10 сентября 2017 года):

Обратите внимание, что первоначальная служба Renderer теперь устарела пользу Renderer2

как на официальный документ Renderer2

Кроме того, как указал @GünterZöchbauer:

На самом деле использование ElementRef в порядке. Также используя ElementRef.nativeElement с Renderer2 в порядке. Что обескураживает напрямую обращается к свойствам ElementRef.nativeElement.xxx.


Вы можете достичь этого, используя elementRef, а также ViewChild. однако не рекомендуется использовать elementRef из-за:

  • проблема с безопасностью
  • плотная муфта

как указано официальная документация ng2.

Использование elementRef (прямой доступ):

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

Использование ViewChild (лучший подход):

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

  constructor(private renderer: Renderer2) {}  //<-- changed to Renderer2 

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

  }
}

Ответ 3

Angular 2.0.0 Финал:

Я обнаружил, что использование установщика ViewChild является самым надежным способом установки начального фокуса управления форматом:

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

Сетью сначала вызывается значение undefined, за которым следует вызов с инициализированным ElementRef.

Рабочий пример и полный источник здесь: http://plnkr.co/edit/u0sLLi?p=preview

Использование TypeScript 2.0.3 Final/RTM, Angular 2.0.0 Final/RTM и Chrome 53.0.2785.116 м (64-разрядная версия).

UPDATE для Angular 4 +

Renderer устарел в пользу Renderer2, но Renderer2 не имеет invokeElementMethod. Вам нужно будет напрямую обратиться к DOM, чтобы установить фокус, как в input.nativeElement.focus().

Я все еще нахожу, что подход сеттера ViewChild работает лучше всего. При использовании AfterViewInit я иногда получаю ошибку 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);
    }
}