Как выбрать элемент в шаблоне компонента?
Как получить доступ к элементам, определённым в шаблоне компонента? В Polymer это делается легко с помощью $
и $$
.
Я задаюсь вопросом, как это реализовать в Angular.
Рассмотрим пример из учебника:
import {Component} from '@angular/core';
@Component({
selector: 'display',
template: `
<input #myname (input)="updateName(myname.value)"/>
<p>My name : {{myName}}</p>
`
})
export class DisplayComponent {
myName: string = "Aman";
updateName(input: String) {
this.myName = input;
}
}
Как мне получить ссылку на элемент <p>
или <input>
из определения класса?
5 ответ(ов)
Вы можете получить доступ к элементу DOM через ElementRef
, инжектируя его в конструктор вашего компонента:
constructor(private myElement: ElementRef) { ... }
Документация: ElementRef
Для тех, кто пытается получить экземпляр компонента внутри *ngIf
или *ngSwitchCase
, вы можете воспользоваться следующим трюком.
Создайте директиву init
.
import {
Directive,
EventEmitter,
Output,
OnInit,
ElementRef
} from '@angular/core';
@Directive({
selector: '[init]'
})
export class InitDirective implements OnInit {
constructor(private ref: ElementRef) {}
@Output() init: EventEmitter<ElementRef> = new EventEmitter<ElementRef>();
ngOnInit() {
this.init.emit(this.ref);
}
}
Экспортируйте свой компонент с именем, например, myComponent
@Component({
selector: 'wm-my-component',
templateUrl: 'my-component.component.html',
styleUrls: ['my-component.component.css'],
exportAs: 'myComponent'
})
export class MyComponent { ... }
Используйте этот шаблон, чтобы получить как ElementRef
, так и экземпляр MyComponent
<div [ngSwitch]="type">
<wm-my-component
#myComponent="myComponent"
*ngSwitchCase="Type.MyType"
(init)="init($event, myComponent)">
</wm-my-component>
</div>
Используйте следующий код в TypeScript
init(myComponentRef: ElementRef, myComponent: MyComponent) {
}
Таким образом, с помощью этой директивы вы сможете легко получать доступ к экземпляру компонента даже внутри структурных директив, таких как *ngIf
или *ngSwitchCase
.
Ваш код компонента Angular содержит несколько моментов, которые нуждаются в исправлении, чтобы он работал корректно. Вот исправленный вариант:
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
selector: 'display',
template: `
<input #myname (input)="updateName(myname.value)" />
<p> My name: {{ myName }}</p>
`
})
export class DisplayComponent {
@ViewChild('myname') inputTxt: ElementRef; // Создаем ViewChild
myName: string;
constructor() {
this.myName = "Aman";
}
updateName(input: string) { // Объявляем метод
this.myName = input; // Обновляем значение myName
this.inputTxt.nativeElement.value = this.myName; // Задаем значение элементу input
}
}
Изменения и пояснения:
- Исправлен синтаксис компонента: В шаблоне отсутствовала запятая после селектора.
- Метод
updateName
: Я перенес его определение вне конструктора, чтобы это было более стандартным подходом в Angular. - Использование
this
: Теперьthis.myName
обновляется непосредственно входным значением, а не задается равным ранее инициализированной строке.
Теперь, когда вы введете текст в поле ввода, он будет обновлять и отображать имя правильно.
Я использовал два способа для получения ссылки на элемент DOM в Angular:
Первый способ:
Вы можете получить доступ к элементу DOM через ElementRef
, инъектируя его в конструктор вашего компонента:
constructor(private myElement: ElementRef) {
this.myElement.nativeElement; // <- ваша прямая ссылка на элемент
}
Второй способ:
Вы также можете использовать декоратор @ViewChild
для получения ссылки на элемент после его инициализации:
@Component({
selector: 'my-app',
template: `
<input #input value="enterThere">
`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
@ViewChild('input') input: ElementRef;
ngAfterViewInit() {
console.log(this.input);
}
}
Оба способа позволяют получить доступ к элементу, но @ViewChild
рекомендуется использовать, когда вам нужно работать с элементом после того, как он был загружен в представление.
Примечание: Это не применимо к Angular 6 и выше, так как ElementRef
стал ElementRef<T>
, где T
обозначает тип nativeElement
.
Я хотел бы добавить, что если вы используете ElementRef
, как рекомендуется во всех ответах, то вы сразу столкнетесь с проблемой, что у ElementRef
ужасное объявление типа, которое выглядит следующим образом:
export declare class ElementRef {
nativeElement: any;
}
Это абсурдно в среде браузера, где nativeElement
является HTMLElement
.
Чтобы обойти это, вы можете использовать следующую технику:
import { Inject, ElementRef as ErrorProneElementRef } from '@angular/core';
interface ElementRef {
nativeElement: HTMLElement;
}
@Component({...})
export class MyComponent {
constructor(@Inject(ErrorProneElementRef) readonly elementRef: ElementRef) { }
}
Этот подход позволит вам безопасно использовать nativeElement
как HTMLElement
, избегая потенциальных проблем, связанных с типизацией.
Как динамически назначить свойства объекту в TypeScript?
Как удалить элемент массива в TypeScript?
Что такое "*.d.ts" в TypeScript?
TypeScript ошибка TS2304: не удается найти имя 'require'
Как определить тип для функции-коллбэка (как любой тип функции, а не универсальный any) в параметре метода