Как выбрать элемент в шаблоне компонента?
Как получить доступ к элементам, определённым в шаблоне компонента? В 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, избегая потенциальных проблем, связанных с типизацией.
Нет провайдера для HttpClient
@Directive против @Component в Angular
Разница между ViewEncapsulation.Native, ViewEncapsulation.None и ViewEncapsulation.Emulated в Angular
Как использовать enum в компоненте Angular
Компилятор Angular требует TypeScript версии >=2.7.2 и <2.8.0, но найдена версия 2.8.3