1

How do I pass a value between child components that are populated using *ngFor ?.

I have tried using the @output decorator patterns and it results in erroneous behavior.

  1. How do to correctly use the @output. why does the expected results are not obtained. ?
  2. Is there any other way to achieve this functionality other than changing the data model?.

A JSON array is specified app.component.ts and it has a field salary. I would want to display a total field salary as we loop through the array and display it in the child component.

Here the goal is to print out the total salary dynamically as the elements get iterated. I try to achieve this using @output decorator by calculating the total salary of the child and then send it to the parent.

app.component.html

<div *ngFor="let person of persons">
<app-child [name]="person.name" [salary]= "person.salary" [totalsalary] = "totalsalary" 
(totalSalary)="setTotalSalary($event)">

 </app-child>
 <div>

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

app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  @Input() totalsalary:number=0;

persons = [{
  "name":"x",
  "salary":1
},{
  "name":"s",
  "salary":2
},
{
  "name":"y",
  "salary":2
}
]
setTotalSalary(totalSalary:number) {
 //   console.log("total  salary" +this.totalsalary)
  this.totalsalary = totalSalary;
}
}

child.component.ts

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

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {

  @Input() name!:string;
  @Input() salary!:number;
  @Input() totalsalary!:number;
  @Output() totalSalary = new  EventEmitter<number>();

  constructor() { }

  ngOnInit(): void {
  }

  displayTotalSalary() {
    console.log("current salary"+this.salary)
    console.log("total  salary" +this.totalsalary)
let sum = Number(this.salary) + Number(this.totalsalary)
    this.totalSalary.emit(sum);
    return  Number(sum)
  }

}

child.component.html

<p>{{name}}</p>
<p>{{salary}}</p>
<p>{{displayTotalSalary()}}</p>

Expected Result :

x

1

1

s

2

3

y

2

5

Received :

x

1

6

s

2

8

y

2

10
Sree
  • 1,694
  • 1
  • 18
  • 29
  • 1
    so you want to take the prev salary and add current salary and show it in that UI? If that is the case why don't you calculate total on your dataset level. – Vimal Patel Jan 09 '21 at 13:34
  • @vimPatel just exploring my options and trying to learn stuff. Ideally what you say is correct. – Sree Jan 09 '21 at 14:20

1 Answers1

2

displayTotalSalary() is being called two times for each child, first time for each child(taking the totalSalary to 1+2+2 =5) then again for each child that's why you are getting 5+1=6, 6+2=8 and 8+2=10.

This is because of the function call displayTotalSalary() in template, moving the call from template to the ts files fixes the issue.

ngOnInit(): void { this.salaryToDisplay = this.displayTotalSalary(); }

and in child template use<p>{{salaryToDisplay}}</p>

To know why function call in template is being called multiple times.

Ashish Dahiya
  • 650
  • 5
  • 14