Exploring ways to establish communication between parent and child components through click events

I am currently working on an Angular 8 application that involves a parent-child relationship.

The parent component, DossierCorrespondenceComponent, contains a function that needs to be triggered from within the child component.

This is the function in the parent component:

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

When trying to call this function in the child component, DossierCorrespondenceListComponent, I used the following code:

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

However, nothing happens when this interaction takes place.

So, what changes do I need to make to resolve this issue?

In addition, another component, DossierCorrespondenceAttachmentsComponent, also needs to utilize the same function:

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

If I move the function gotoItem(index, type: string) to both child components, it will result in duplicate code.

Currently, the parent component is structured as follows:

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

And the TypeScript code in the 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;
}

For the 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 the TypeScript code in the 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();
  }

}

However, after making these changes, I encountered the following 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)

To address this issue, I made the following change:

 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 

Answer №1

Main Component :

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

navigateToItem() {
    //perform action
}

Sub Component :

<tr class="correspondence-row" *ngFor="let entry of attachmentEntries; let i = index" (click)="handleClick()">

@Output() onClick = new EventEmitter();

handleClick() {
    // perform action
    this.onClick.emit()
}

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

Main Component (html)

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

Main Component (ts)

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

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

  navigateToItem(event) {
    console.log(event)
  }

}

Sub Component

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

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

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

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

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

}

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

Answer №2

Within the parent component:

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

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

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

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

Now, for the 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();
 }
}

For reference, a StackBlitz demo has been set up:

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

Answer №3

CommunicationModuleComponent.html :

<app-child (triggerFunction)="executeFunction()"</app-child>

CommunicationModuleComponent.ts :

executeFunction() {
}

child.component.ts

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

@Output() triggerFunction = new EventEmitter();

When you want to trigger the parent component:

this.triggerFunction.emit(true)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issues with updating values in Angular form controls are not being resolved even with the use of [formControl].valueChanges

[formControl].valueChanges is not triggering .html <span>Test</span> <input type="number" [formControl]="testForm"> .ts testData: EventEmitter<any> = new EventEmitter<any>(); testForm: FromCo ...

Obtain data from the DOM using ng-select in Angular 10

In my Angular 10 project, I have certain views where I utilize ng-select to showcase and obtain data. The QA team has tests in place that depend on element id and DOM value, specifically designed for basic select elements. With a simple select, we are able ...

Having trouble with clearInterval in my Angular code

After all files have finished running, the array this.currentlyRunning is emptied and its length becomes zero. if(numberOfFiles === 0) { clearInterval(this.repeat); } I conducted a test using console.log and found that even though ...

Storing and sharing information between routes in Angular 2: The ultimate guide

As I launch my angular app, I make a request to an endpoint during initialization to retrieve data for specific routes. When I navigate to the home page, I fetch the home page data from the database and return it. Similarly, when I go to the contact route, ...

Ways to transfer selected options from a dropdown menu to a higher-level component

I am currently in the process of configuring a modal component that showcases various data from a specific record to the user. The user is provided with a Bulma dropdown component for each field, enabling them to make changes as needed. To streamline the c ...

Any idea how to resolve this typescript typing issue: "The argument, either a string or number, cannot be assigned to the parameter of type 'SetStateAction<string>'"?

Just recently delving into TypeScript, I've encountered a persistent typing problem that has proven challenging to resolve despite numerous attempts. The error message causing me trouble reads as follows: Argument of type 'string | number' ...

Managing Import Structure in Turborepo/Typescript Package

I am currently working on creating a range of TypeScript packages as part of a Turborepo project. Here is an example of how the import structure for these packages looks like: import { Test } from "package-name" import { Test } from "package ...

Tips on handling communication between different feature modules each handling their own portion of the state

I am currently working on an Angular application that consists of multiple feature modules. My goal is to implement ngrx store in such a way that each module manages its own state. // app.module.ts ... imports: [ ... StoreModule.forRoot(reducers) ...

Protected members in Angular 2 component templates using TypeScript

Reflecting on ways to incorporate members in a component that can be accessed from the template but not from a parent component sparked my curiosity. In exploring TypeScript visibility in Angular 2, I encountered discussions about "public" and "private" d ...

Executing a PHP function within a Laravel controller using Ajax

In my Laravel project, I have a Controller named Clientecontroller that is working perfectly. It contains a method called listar() which retrieves client information. public function listar(Cliente $cliente) { $clientes = DB::table('clientes' ...

What causes multiple links to have an active class when using Angular2's routerLinkActive?

I am currently trying to incorporate routerLinkActive into my application, but I am encountering an issue where the active class is being applied to multiple links. Here's how I have implemented it: <ul class="nav nav-tabs"> <li r ...

Edge is experiencing a slowdown when utilizing ng-bind-html

I've been using ng-bind-html to bind HTML content to a div element. However, when I attempt to bind larger amounts of HTML, it can take around 5-6 seconds for the content to load. Interestingly, this issue seems to only occur in Chrome browser. I have ...

npm WARNING: The package @angular-devkit/[email protected] is in need of a peer dependency xxxx, however no installation for this dependency has

Attempting to launch an angular project and encountering the following errors: $ npm install npm WARN @angular-devkit/[email protected] requires a peer of @angular/compiler-cli@^14.0.0 but none is installed. You must install peer dependencies yoursel ...

Problem encountered while implementing callbacks in redux-saga

I am facing a scenario in which I have a function called onGetCameras that takes a callback function named getCamerasSuccess. The idea is to invoke the external function onGetCameras, which makes an AJAX call and then calls getCamerasSuccess upon completio ...

Utilize multiple validators.patterns within a single value for enhanced data validation

I need to implement two different patterns for the formControlName='value' based on the type selected. If type is 'A', I want to use the valuePattern, and if type is 'B', I want to use the uname pattern. This is my HTML code: ...

Angular 5: Steps to send an event from authguard to header in Angular application

I am struggling to send out an event from the authguard component to the header component. Event broadcasting setup @Injectable() export class BroadcastService { public subject = new Subject<any>(); sendMessage(message: string) { this.subjec ...

Instruction to pay attention to the event

After noticing that I've added similar event listening code to many of my controllers, I began to think about how to streamline it. The code looks something like this: document.addEventListener("resume", function(e){ $scope.doSomething(); }, ...

What sets apart calling an async function from within another async function? Are there any distinctions between the two methods?

Consider a scenario where I have a generic function designed to perform an upsert operation in a realmjs database: export const doAddLocalObject = async <T>( name: string, data: T ) => { // The client must provide the id if (!data._id) thr ...

Unit testing Angular components involves testing a service creation through an interface

Consider this scenario where a component creates a local service: @Component({ <removed for clarity> providers: [ { provide: 'IMyService', useClass: MyService }, ] }) export class MyComponent implements OnInit, OnDestro ...

Dynamic cell loading in Vue using Vuetify's datatable functionality

<template> <v-data-table :headers="headers" :items="records" :items-per-page="5" show-select loading item-key="id" class="elevation-1" > <template v-slot:top> <div> <table-tabs> ...