mightycode Newton
mightycode Newton

Reputation: 3949

How to communicate parent child component with click event

I have a Angular 8 application. And I have a Parent and child relationship.

So I have a function in a parent DossierCorrespondenceComponent, but the function has to be triggererd in the child component.

So I have this function in the parent:

@Input()  myGotoItem: Function;


gotoItem(index, type: string) {
    this.showingSingle = true;

    switch (type) {
      case 'correspondence': {
        this.single = this.correspondenceEntries[index];
        break;
      }
      case 'attachments': {
        this.single = this.attachmentEntries[index];
        break;
      }
      default: {
        break;
      }
    }
    this.showingSingle = true;
  }

And I try to call it in the child component DossierCorrespondenceListComponent like this :

 <tr class="dossier-correspondencerow" *ngFor="let entry of correspondenceEntries; let i = index" (myGotoItem)="gotoItem(i, entry.type)">

But nothing happens

So what I have to change?

But I have a other component DossierCorrespondenceAttachmentsComponent who also uses that function:

 <tr class="dossier-correspondencerow" *ngFor="let entry of attachmentEntries; let i = index" (click)="gotoItem(i, entry.type)">

So If I have to move the function gotoItem(index, type: string) to both the child components than I have duplicate code.

I have it now like this in parent component:

<ng-container *ngIf="correspondenceEntries">
    <app-dossier-correspondence-list [correspondenceEntries]="correspondenceEntries" (onClick)="gotoItem(i, entry.type)"> </app-dossier-correspondence-list>
  </ng-container>

and ts parent component:

gotoItem(index, type: string) {
    this.showingSingle = true;

    switch (type) {
      case 'correspondence': {
        this.single = this.correspondenceEntries[index];
        break;
      }
      case 'attachments': {
        this.single = this.attachmentEntries[index];
        break;
      }
      default: {
        break;
      }
    }
    this.showingSingle = true;
  }

and child component:

  <tbody class="dossier-tablebody">
          <tr class="dossier-correspondencerow" *ngFor="let entry of correspondenceEntries; let i = index" (click)="gotoItem(i, entry.type)">
            <td>{{ entry.date | date:"dd-MM-y" }}</td>
            <td>{{ entry.name }}</td>
          </tr>
        </tbody>



and ts child component:


export class DossierCorrespondenceListComponent implements OnInit {

  @Input()
  correspondenceEntries: DossierEntry[];

  @Output()
  onClick = new EventEmitter();

  @Input() showingSingle;

  constructor() { }

  ngOnInit() {
  }

  ngOnChanges(changes) { console.log(changes)}

  click() {
    this.onClick.emit();
  }


}

But then I get this error:

dossier-correspondence-list.component.html:13 ERROR TypeError: _co.gotoItem is not a function
    at Object.handleEvent (dossier-correspondence-list.component.html:13)
    at handleEvent (core.js:29733)
    at callWithDebugContext (core.js:30803)
    at Object.debugHandleEvent [as handleEvent] (core.js:30530)
    at dispatchEvent (core.js:20520)
    at core.js:28942
    at HTMLTableRowElement.<anonymous> (platform-browser.js:1009)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:26760)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)

and I changed this:

 click() {
    this.onClick.emit(true);
  }

dossier-correspondence-item.component.ts:51 ERROR TypeError: _co.gotoItem is not a function
    at Object.handleEvent (dossier-correspondence-item.component.ts:51)
    at handleEvent (core.js:29733)
    at callWithDebugContext (core.js:30803)
    at Object.debugHandleEvent [as handleEvent] (core.js:30530)
    at dispatchEvent (core.js:20520)
    at core.js:28942
    at HTMLTableRowElement.<anonymous> (platform-browser.js:1009)
    at 

Upvotes: 4

Views: 9659

Answers (3)

Jonas Woo
Jonas Woo

Reputation: 66

Parent component :

<child (onClick)="gotoItem()"></child>

gotoItem() {
    //do something
}

Child component :

<tr class="dossier-correspondencerow" *ngFor="let entry of attachmentEntries; let i = index" (click)="click()">

@Output() onClick = new EventEmitter();

click() {
    // do something
    this.onClick.emit()
}

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

Parent component(html)

<app-dossier-correspondence-list [correspondenceEntries]="correspondenceEntries" (onClick)="gotoItem($event)"> </app-dossier-correspondence-list>

Parent component(ts)

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

  gotoItem(e) {
    console.log(e)
  }

}

Child component

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

@Component({
  selector: 'app-dossier-correspondence-list',
  template: `
    <table>
      <tr *ngFor="let entry of attachmentEntries; let i = index" (click)="click(i, entry.type)">
        {{entry.type}}
      </tr>
    </table>
  `
})
export class AppDossierCorrespondenceComponent  {

  @Input() correspondenceEntries: any;
  @Output() onClick = new EventEmitter();

  attachmentEntries = [
    { type: 'type1' },
    { type: 'type2' },
    { type: 'type3' },
  ]

  click(i, type) {
    this.onClick.emit({
      i: i,
      type: type
    })
  }

}

Link: https://stackblitz.com/edit/angular-ev6e5n

Upvotes: 5

Adrita Sharma
Adrita Sharma

Reputation: 22203

DossierCorrespondenceComponent.html :

<app-child (callYourFunction)="yourFunction()"</app-child>

DossierCorrespondenceComponent.ts :

yourFunction() {
}

child.component.ts

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

@Output() callYourFunction = new EventEmitter();

At the event you want to call parent component:

this.callYourFunction.emit(true)

Upvotes: 1

Prawin soni
Prawin soni

Reputation: 452

Parent component:

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

@Component({
 selector: 'my-app',
 template: `
  <hello [name]="name" (callParentFunc)="parentFunc()"></hello>
  <p [class.red]="clicked">
   This is text from parent component
  </p>
 `,
 styles: [`
  p {
   font-family: Lato;
  }

  p.red {
   color: red;
  }
`]
})
export class AppComponent  {
 name = 'Click me';
 clicked: boolean;

 parentFunc() {
  this.clicked = !this.clicked;
 }
}

Child component:

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

@Component({
 selector: 'hello',
 template: `<h1>
 Child component <a (click)="childClick()">{{name}}</a>
  </h1>`,
 styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
 @Input() name: string;
 @Output() callParentFunc: EventEmitter<any> = new EventEmitter<any>();

 childClick() {
  this.callParentFunc.emit();
 }
}

I've created stackblitz for you, this might help:

https://stackblitz.com/edit/angular-c9egd6

Upvotes: 1

Related Questions