Angular: как получить доступ к компоненту внутри ‹ng-content› с помощью @ContentChild

При создании компонентов в Angular иногда нам нужно поместить один компонент внутрь другого. Для этого мы можем либо объявить компонент в шаблоне другого компонента, либо использовать проекцию контента и поместить компонент внутри тегов другого компонента. В этой статье я покажу вам, как родительский компонент может получить доступ к свойствам компонента, размещенного с помощью проекции содержимого.

1. Создайте новый проект

Во-первых, давайте создадим новый проект. Если вы не знаете, как это сделать, рекомендую мою статью, где вы найдете инструкцию как создать новый проект в Angular.

2. Создайте CarDescriptionComponent

Давайте создадим компонент CarDescription, используя следующую команду:

ng g c car-description

В этом компоненте мы объявим две переменные: «description», в которой будет храниться описание автомобиля, и «price», в которой будет храниться его цена. Код компонента ниже:

import { Component } from '@angular/core';
@Component({
  selector: 'app-car-description',
  template: `<p>{{description}}</p>`,
  styleUrls: ['./car-description.component.css']
})
export class CarDescriptionComponent {
  description: string = 'This car will provide you with an amazing experience, and its performance will ensure that you will never want to drive anything else.';
  price: number = 10000;
}

3. Создайте автомобильный компонент

Теперь давайте создадим CarComponent с помощью следующей команды:

ng g c car

Затем введите код ниже:

import { ContentChild } from '@angular/core';
import { AfterViewInit } from '@angular/core';
import { Component } from '@angular/core';
import { CarDescriptionComponent } from '../car-description/car-description.component';
@Component({
  selector: 'app-car',
  template: `<h1>Ford Mustang</h1>
    <ng-content select="[description]"></ng-content>`,
  styleUrls: ['./car.component.css']
})
export class CarComponent implements AfterViewInit { }

В этом компоненте мы разместили тег ‹ng-content›, благодаря которому можно будет проецировать контент. Содержимое будет отображаться только в том случае, если компонент, который мы хотим поместить внутрь, будет помечен директивой «описание». Это условие указано в директиве select.

4. Показать компоненты

Чтобы увидеть, как работает наше простое приложение, вставьте приведенный ниже код в файл app.component.html:

<app-car>
  <app-car-description></app-car-description>
</app-car>

Компонент app-car-description будет помещен внутри тегов ‹ng-content› в CarComponent благодаря директиве «description». После запуска мы должны получить такой вид:

5. Используйте @ContentChild

Если мы хотим не только отобразить компонент, но и получить доступ к его переменным, пригодится атрибут @ContentChild, который позволяет получить доступ к переменным, содержащимся в компоненте, размещенном внутри ‹ng-content›. В файл car.component.ts поместите следующий код:

export class CarComponent implements AfterViewInit {
@ContentChild(CarDescriptionComponent) carDescription: CarDescriptionComponent
ngAfterViewInit() {
  console.log(this.carDescription);
  const price = this.carDescription.price;
  console.log('price from carDescription: ', price);
}

Когда мы открываем консоль браузера, мы должны увидеть это:

Как видите, благодаря декоратору @ContentChild мы получили доступ к переменным внутри CarDescriptionComponent. При использовании @ContentChild важно добраться до компонента после его инициализации — для этого я использовал хук «ngAfterViewInit()». Если мы сошлемся на этот компонент перед его инициализацией, например, с помощью «ngOnInit()», мы получим «undefined». Если мы хотим получить доступ к компоненту в «ngOnInit()», мы должны использовать «static: true», как показано ниже:

@ContentChild(CarDescriptionComponent, { static: true}) carDescription: CarDescriptionComponent

Краткое содержание

Благодаря атрибуту @ContentChild мы можем получить доступ к переменным в компоненте, который хотим поместить внутрь ‹ng-content›. Однако не забывайте использовать правильный хук.