Как получить элемент 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);
}
}