7

Как выбрать элемент в шаблоне компонента?

1

Как получить доступ к элементам, определённым в шаблоне компонента? В 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 ответ(ов)

2

Вы можете получить доступ к элементу DOM через ElementRef, инжектируя его в конструктор вашего компонента:

constructor(private myElement: ElementRef) { ... }

Документация: ElementRef

0

Для тех, кто пытается получить экземпляр компонента внутри *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.

0

Ваш код компонента 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
  }
}

Изменения и пояснения:

  1. Исправлен синтаксис компонента: В шаблоне отсутствовала запятая после селектора.
  2. Метод updateName: Я перенес его определение вне конструктора, чтобы это было более стандартным подходом в Angular.
  3. Использование this: Теперь this.myName обновляется непосредственно входным значением, а не задается равным ранее инициализированной строке.

Теперь, когда вы введете текст в поле ввода, он будет обновлять и отображать имя правильно.

0

Я использовал два способа для получения ссылки на элемент 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 рекомендуется использовать, когда вам нужно работать с элементом после того, как он был загружен в представление.

0

Примечание: Это не применимо к 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, избегая потенциальных проблем, связанных с типизацией.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь