1
votes

I've this parent-child components in Angular and I'm trying to pass an object from the child component to the parent in order to update a value from the parent's object array. I've been followint the angular documentation example but seems like it's not sending the new object to the paren component but it's not showing any error neither the console or the VSC terminal.

This is the angular guide I followed: https://angular.io/guide/inputs-outputs#sending-data-to-a-parent-component

Parent view:

<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 {
  }
}

Child view:

<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>

Child controller:

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 };
  }

}

When I click on the button I se the console.log that the addNewItem it's executing but on the addItem on the parent component function I don't see the console.log, the goal is to pass the id and customer's name so I can update the customers array with the customer's new information

2
The <router-outlet> cannot accept the emitted event. If you review the tutorial very carefully, you'll see the event is caught on the Parent component's selector.Randy Casburn
Yes I saw it but the <router-outlet> it's the element I have to place the child component inside the parent component. On my app.component.html I just have the header component which is always the same on the whole app and a router outlet. If this is not possible what chances do I have?jcobo1
Right - so you've tried to improvise on the Angular tut - I get that, but Angular is too complicated to hack at in the fashion. But since you're making progress, you should look at data management using services to help you solve your problem for you. It is how most enterprise applications are written.Randy Casburn
Services seems more likely to work I will work with this thanks for the link 👌🏻👌🏻jcobo1

2 Answers

1
votes

The router outlet component is just a marker that is used by the angular router in order to know where to place the components being rendered for the different routes. Placing an event listener on this component will result in nothing since it's not the actual route component.

You could use a service or do something like this:

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. Query the router outlet component

  2. Listen for the navigation end event in order to get notified whenever the component for the route has changed.

  3. Get the current component instance and do something on it. In your case you will have an event emitter and you can subscribe for the event.

Here I'm assuming that this will be used in the AppComponent and I haven't unsubscribed but if you attend to use it in an inner component where you have a named outlet and the component might get destroyed at some time, make sure that you unsubscribe from the stream in order to prevent memory leaks.

0
votes

THe main reason why this is not working it's becasuse as @user1 mentioned the <router-outlet> can not receive parameters like a component would do. Also, his proposal about creating a service to share all the information between components it's the most appropiate and the recomended by the Angular documentation: https://angular.io/tutorial/toh-pt4