Поиск по сайту:

Как использовать ViewChild в Angular для доступа к дочернему компоненту, директиве или элементу DOM


Введение

Эта статья познакомит вас с декоратором Angular ViewChild.

Могут быть ситуации, когда вы хотите получить доступ к директиве, дочернему компоненту или элементу DOM из класса родительского компонента. Декоратор ViewChild возвращает первый элемент, соответствующий заданной директиве, компоненту или селектору ссылки на шаблон.

Предпосылки

Если вы хотите следовать этому руководству:

  • Рассмотрите возможность установки @angular/cli.
  • Используйте @angular/cli, чтобы создать новый проект для тестирования функциональности ViewChild.

Это руководство было проверено с помощью @angular/core v13.0.2 и @angular/cli v13.0.3.

Использование ViewChild с директивами

ViewChild позволяет получить доступ к директивам.

Допустим, у вас есть SharkDirective. Эта директива будет искать элементы с атрибутом appShark и добавлять к тексту элемента слово Shark.

В идеале вы будете использовать @angular/cli для генерации вашей директивы:

  1. ng generate directive shark --skip-tests

Эта команда создаст файл shark.directive.ts. И добавляет директиву в app.module.ts:

import { SharkDirective } from './shark.directive';
...
@NgModule({
  declarations: [
    AppComponent,
    SharkDirective
  ],
  ...
})

Затем используйте ElementRef и Renderer2, чтобы переписать текст. Замените содержимое shark.directive.ts следующим:

import {
  Directive,
  ElementRef,
  Renderer2
} from '@angular/core';

@Directive(
  { selector: '[appShark]' }
)
export class SharkDirective {
  creature = 'Dolphin';

  constructor(elem: ElementRef, renderer: Renderer2) {
    let shark = renderer.createText('Shark ');
    renderer.appendChild(elem.nativeElement, shark);
  }
}

Затем добавьте атрибут appShark в span, содержащий текст в шаблоне компонента. Замените содержимое app.component.html следующим:

<span appShark>Fin!</span>

При просмотре приложения в браузере оно отобразит слово Shark перед содержимым элемента:

Output
Shark Fin!

Теперь вы также можете получить доступ к переменной экземпляра creature в SharkDirective и установить переменную экземпляра extraCreature с ее значением. Замените содержимое app.component.ts следующим:

import {
  Component,
  ViewChild,
  AfterViewInit
} from '@angular/core';
import { SharkDirective } from './shark.directive';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
  extraCreature!: string;

  @ViewChild(SharkDirective)
  set appShark(directive: SharkDirective) {
    this.extraCreature = directive.creature;
  };

  ngAfterViewInit() {
    console.log(this.extraCreature); // Dolphin
  }
}

Этот код использовал сеттер для установки переменной extraCreature. Обратите внимание, что он ожидает, пока хук жизненного цикла AfterViewInit получит доступ к переменной, так как именно тогда становятся доступными дочерние компоненты и директивы.

При просмотре приложения в браузере вы по-прежнему будете видеть сообщение Акулий плавник!. Однако в журнале консоли будет отображаться:

Output
Dolphin

Родительский компонент смог получить доступ к значению из директивы.

Использование ViewChild с элементами DOM

ViewChild позволяет получить доступ к собственным элементам DOM, у которых есть ссылочная переменная шаблона.

Допустим, у вас есть <input> в шаблоне со ссылочной переменной #someInput. Замените содержимое app.component.html следующим:

<input #someInput placeholder="Your favorite sea creature">

Теперь вы можете получить доступ к <input> с помощью ViewChild и установить value. Замените содержимое app.component.ts следующим:

import {
  Component,
  ViewChild,
  AfterViewInit,
  ElementRef
} from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
  @ViewChild('someInput') someInput!: ElementRef;
  ngAfterViewInit() {
    this.someInput.nativeElement.value = 'Whale!';
  }
}

Когда ngAfterViewInit срабатывает, значение <input> будет установлено на:

Output
Whale!

Родительский компонент смог установить значение дочернего элемента DOM.

Использование ViewChild с дочерними компонентами

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

Допустим, у вас есть PupComponent.

В идеале вы будете использовать @angular/cli для генерации вашего компонента:

  1. ng generate component pup --flat --skip-tests

Эта команда создаст файлы pup.component.ts, pup.component.css и pup.component.html. И добавляет компонент в app.module.ts:

import { PupComponent } from './pup.component';
...
@NgModule({
  declarations: [
    AppComponent,
    PupComponent
  ],
  ...
})

Затем добавьте метод whoAmI в PupComponent, который возвращает сообщение:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-pup',
  templateUrl: './pup.component.html',
  styleUrs: ['./pup/component.css']
})
export class PupComponent implements OnInit {

  constructor() { }

  whoAmI() {
    return 'I am a pup component!';
  }

  ngOnInit(): void {
  }

}

Затем укажите ссылку на дочерний компонент в шаблоне приложения. Замените содержимое app.component.html следующим:

<app-pup>pup works!</app-pup>

Теперь вы можете вызвать метод whoAmI из класса родительского компонента с помощью ViewChild. Замените содержимое app.component.ts следующим:

import {
  Component,
  ViewChild,
  AfterViewInit
} from '@angular/core';
import { PupComponent } from './pup.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterViewInit {
  @ViewChild(PupComponent) pup!: PupComponent;
  ngAfterViewInit() {
    console.log(this.pup.whoAmI()); // I am a pup component!
  }
}

При просмотре приложения в браузере в журнале консоли будет отображаться:

Output
I am a pup component!

Родительский компонент смог вызвать метод whoAmI дочернего компонента.

Заключение

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

Если ссылка изменяется на новый элемент динамически, ViewChild автоматически обновит свою ссылку.

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

Если вы хотите узнать больше об Angular, ознакомьтесь с нашей темой по Angular, где вы найдете упражнения и проекты по программированию.