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

В Angular есть несколько способов передачи данных из дочернего компонента в родительский. Вот некоторые из них:

1. Использование событий:
В дочернем компоненте можно создать событие, которое будет возникать при изменении данных. Для этого в дочернем компоненте создается Output-свойство с помощью декоратора @Output(). Когда происходит изменение данных, компонент генерирует событие с помощью метода emit(). Затем в родительском компоненте можно подписаться на это событие с помощью привязки событий.

Пример:

Дочерний компонент:

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

   @Component({
     selector: 'app-child',
     template: `
       <button (click)="updateData()">Update Data</button>
     `
   })
   export class ChildComponent {
     @Output() dataUpdated = new EventEmitter<string>();

     updateData() {
       const newData = 'New data from child component';
       this.dataUpdated.emit(newData);
     }
   }

Родительский компонент:

   <app-child (dataUpdated)="onDataUpdated($event)"></app-child>
   <p>{{ dataFromChild }}</p>
   import { Component } from '@angular/core';

   @Component({
     selector: 'app-parent',
     template: `
       <app-child (dataUpdated)="onDataUpdated($event)"></app-child>
       <p>{{ dataFromChild }}</p>
     `
   })
   export class ParentComponent {
     dataFromChild: string;

     onDataUpdated(newData: string) {
       this.dataFromChild = newData;
     }
   }

При нажатии кнопки в дочернем компоненте будет сгенерировано событие dataUpdated, которое будет передавать новые данные (newData) в родительский компонент. Затем в родительском компоненте метод onDataUpdated() примет эти данные и сохранит их в своей переменной, чтобы их можно было отобразить на странице.

2. Использование сервиса данных:
Другой способ передачи данных из дочернего компонента в родительский - использование сервиса данных. Создайте сервис, который будет содержать общие данные для родительского и дочернего компонента. Дочерний компонент может изменять значения в сервисе данных, а родительский компонент может получать эти изменения через инъекцию сервиса и обновлять свои данные соответственно.

Пример:

Сервис данных:

   import { Injectable } from '@angular/core';
   import { BehaviorSubject } from 'rxjs';

   @Injectable({
     providedIn: 'root',
   })
   export class DataService {
     private dataSubject = new BehaviorSubject<string>(null);
     public data$ = this.dataSubject.asObservable();

     updateData(newData: string) {
       this.dataSubject.next(newData);
     }
   }

Дочерний компонент:

   import { Component } from '@angular/core';
   import { DataService } from './data.service';

   @Component({
     selector: 'app-child',
     template: `
       <button (click)="updateData()">Update Data</button>
     `
   })
   export class ChildComponent {
     constructor(private dataService: DataService) {}

     updateData() {
       const newData = 'New data from child component';
       this.dataService.updateData(newData);
     }
   }

Родительский компонент:

   <p>{{ dataFromChild }}</p>
   import { Component, OnInit } from '@angular/core';
   import { DataService } from './data.service';

   @Component({
     selector: 'app-parent',
     template: `
       <p>{{ dataFromChild }}</p>
     `
   })
   export class ParentComponent implements OnInit {
     dataFromChild: string;

     constructor(private dataService: DataService) {}

     ngOnInit() {
       this.dataService.data$.subscribe(newData => {
         this.dataFromChild = newData;
       });
     }
   }

В данном случае в родительском компоненте используется оператор subscribe() для подписки на изменения в сервисе данных. Когда дочерний компонент вызывает updateData(), родительский компонент получает новые данные через сервис данных и обновляет свою переменную для отображения на странице.

3. Использование ViewChild:
Если дочерний компонент является прямым потомком родительского компонента, можно использовать декоратор @ViewChild. Это позволяет родительскому компоненту получить доступ к свойствам и методам дочернего компонента напрямую, без передачи данных явным способом.

Пример:

Дочерний компонент:

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

   @Component({
     selector: 'app-child',
     template: `
       <button (click)="updateData()">Update Data</button>
     `
   })
   export class ChildComponent {
     data = 'Data from child component';

     updateData() {
       this.data = 'New data from child component';
     }
   }

Родительский компонент:

   <app-child></app-child>
   <p>{{ childComponent.data }}</p>
   import { Component, ViewChild } from '@angular/core';
   import { ChildComponent } from './child.component';

   @Component({
     selector: 'app-parent',
     template: `
       <app-child></app-child>
       <p>{{ childComponent.data }}</p>
     `
   })
   export class ParentComponent {
     @ViewChild(ChildComponent) childComponent: ChildComponent;
   }

В данном случае родительский компонент использует @ViewChild для получения доступа к дочернему компоненту, и затем может обращаться к его свойствам и методам напрямую. При нажатии кнопки в дочернем компоненте будет обновлено свойство data, и это обновление будет отображаться на странице в родительском компоненте.