Angular 10 - Event Emmiter не работает - Обмен информацией между дочерним и родительским компонентами

У меня есть родительско-дочерние компоненты в Angular, и я пытаюсь передать объект из дочернего компонента в родительский, чтобы обновить значение из родительского массива объектов. Я следил за примером документации angular, но похоже, что он не отправляет новый объект в компонент paren, но не показывает никаких ошибок ни на консоли, ни на терминале VSC.

Это руководство по angular, которому я следовал: https://angular.io/guide/inputs-outputs#sending-data-to-a-parent-component

Родительский вид:

<h1>Customers list</h1>

<mat-list>
  <a mat-list-item *ngFor="let customr of customers" [routerLink]="[customr.id, {name: customr.name}]">{{ customr.name }}</a>
</mat-list>


<router-outlet (newItemEvent)="addItem($event)"></router-outlet>

Parent controller:

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

@Component({
  selector: 'app-customer-list',
  templateUrl: './customer-list.component.html',
  styleUrls: ['./customer-list.component.scss']
})
export class CustomerListComponent implements OnInit {


  // list = [
  //   { id: 1, name: 'John Smith' },
  //   { id: 2, name: 'Anna Highland' },
  //   { id: 3, name: 'Emilie Poiret' }
  // ];

  customers: Array<Object> = [
    {
      id: 1,
      name: 'John Smith'
    },
    {
      id: 2,
      name: 'Anna Highland'
    },
    {
      id: 3,
      name: 'Emilie Poiret'
    }
  ];

  addItem(customer){
    console.log(`add customer ${customer}`);
  }

  constructor() { }

  updateCustomer(data){
    console.log(data);
  }

  ngOnInit(): void {
  }
}

Детский вид:

<p>{{ name }}</p>


<form [formGroup]="formGroup" (ngSubmit)='addNewItem()'>

  <mat-form-field>
    <mat-label>Customer name:</mat-label>
    <input matInput name="customerName" formControlName="customerName">
  </mat-form-field>

  <button mat-raised-button type="submit">Action</button>

</form>

Дочерний контроллер:

import { ActivatedRoute, Params } from '@angular/router';
import { Component, Input, OnInit } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-customer-detail',
  templateUrl: './customer-detail.component.html',
  styleUrls: ['./customer-detail.component.scss']
})
export class CustomerDetailComponent implements OnInit {

  // https://angular.io/guide/inputs-outputs#sending-data-to-a-parent-component
  @Output() newItemEvent = new EventEmitter<object>();

  formGroup: FormGroup;
  id: string;
  name: string;

  addNewItem(){
  //  console.log(`emit runs ${value}`);
    let id: any = this.id;
    let name = this.formGroup.value.customerName;
    console.log(`id: ${this.id} i name: ${this.formGroup.value.customerName}`);
    let customer = {
      'id': this.id,
      'name': this.formGroup.value.customerName
    };
    console.warn(customer);
    this.newItemEvent.emit(customer);
  }


  constructor(private fb: FormBuilder, private routes: ActivatedRoute) { }

  ngOnInit(): void {

    this.routes.params.subscribe(
      (params: Params) => {
        this.id = params.id;
        this.name = params.name;
      }
    );

    console.log(`ngOnInit ${this.name}`);

    this.buildForm();

  }

  private buildForm(): void {
    console.log(`buildForm ${this.name}`);
    this.formGroup = this.fb.group({
      customerName: [this.name, Validators.required]
    });

  }

  public saveEdit() {
    console.log(`Save edit`);
    return { 'id': this.formGroup.value.customerId, 'name': this.formGroup.value.customerName };
  }

}

Когда я нажимаю кнопку, я вижу console.log, который выполняет addNewItem, но в addItem в функции родительского компонента я не вижу console.log, цель состоит в том, чтобы передать идентификатор и имя клиента, чтобы я мог обновить массив клиентов с новой информацией о клиенте


person kiewlovsky    schedule 18.11.2020    source источник
comment
<router-outlet> не может принять отправленное событие. Если вы внимательно просмотрите руководство, вы увидите, что событие перехватывается селектором родительского компонента.   -  person Randy Casburn    schedule 18.11.2020
comment
Да, я видел это, но ‹router-outlet› это элемент, который я должен разместить дочерний компонент внутри родительского компонента. В моем app.component.html у меня есть только компонент заголовка, который всегда одинаков для всего приложения и выхода маршрутизатора. Если это невозможно, то какие у меня шансы?   -  person kiewlovsky    schedule 18.11.2020
comment
Правильно - значит, вы пытались импровизировать на уроке Angular - я понимаю, но Angular слишком сложен, чтобы взломать его в моде. Но поскольку вы добиваетесь прогресса, вам следует взглянуть на управление данными с помощью служб, чтобы помочь вам решить ваша проблема для вас. Так пишется большинство корпоративных приложений.   -  person Randy Casburn    schedule 18.11.2020
comment
Сервисы вроде с большей вероятностью будут работать Я буду работать с этим спасибо за ссылку ????????????????   -  person kiewlovsky    schedule 18.11.2020


Ответы (2)


Компонент выхода маршрутизатора - это просто маркер, который используется маршрутизатором angular, чтобы знать, где разместить компоненты, визуализируемые для разных маршрутов. Размещение прослушивателя событий на этом компоненте ни к чему не приведет, поскольку это не фактический компонент маршрута.

Вы можете использовать service или сделать что-то вроде этого:

export class AppComponent {
  @ViewChild(RouterOutlet) outlet: RouterOutlet;

  constructor(router: Router) {
    router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
      const c = this.outlet.component;
    });
  }
}
  1. Запросить компонент розетки маршрутизатора

  2. Слушайте событие окончания навигации, чтобы получать уведомления всякий раз, когда компонент для маршрута изменяется.

  3. Получите текущий экземпляр компонента и сделайте с ним что-нибудь. В вашем случае у вас будет эмиттер событий, и вы можете подписаться на событие.

Здесь я предполагаю, что это будет использоваться в AppComponent, и я не отказался от подписки, но если вы захотите использовать его во внутреннем компоненте, где у вас есть именованный выход, и компонент может быть уничтожен в какой-то момент, убедитесь, что вы отказаться от подписки на поток, чтобы предотвратить утечку памяти.

person user1    schedule 25.11.2020

Основная причина, по которой это не работает, потому что, поскольку @ user1 упомянул, что <router-outlet> не может получать параметры, как это делал бы компонент. Кроме того, его предложение о создании службы для обмена всей информацией между компонентами, наиболее подходящими и рекомендованными в документации по Angular: https://angular.io/tutorial/toh-pt4

person kiewlovsky    schedule 25.11.2020