Home > Enterprise >  Reduce Function in Angular Template
Reduce Function in Angular Template

Time:07-21

Is it possible to do a reduce function in the HTML of Angular? I did do this below but it output parsing errors.

HTML

<div *ngIf="report$ | async as report">
  <p>
    {{ report?.payrolls?.reduce((prev, curr) => (prev.gross - prev.c_a - prev.statutory = prev.charges)   (curr.gross - curr.c_a - curr.statutory = curr.charges), 0) | number }}
  </p>
</div>

TS

@Select(ReportState.getEmployeePayslip) report$: Observable<EmployeePayslip>;

CodePudding user response:

You can use the reduce function in your template directly. But what you cannot do is a define a new one, including the lambda that you pass to the reduce function.

So this works:

report?.payrolls?.reduce(accPayloads, 0)

But this does not:

report?.payrolls?.reduce((a, b) => a   b, 0)

The answers on this question explain pretty well why you cannot do that. Additionally, I would strongly recommend you not doing this anyway since angular needs to run these functions during each change detection cycle, which could lead to performance problems. Alternatives are already mentioned in other answers, but to sum it up, it is better to calculate your value reactively - or use a pipe, which memoizes the calculation.

In your case it might also be a good idea to mention a third solution: Create an NGXS Selector which does the computation for you and use that Selector in your Component.

NGXS State
@Selector([ReportState.getEmployeePayslip])
public static progress(report: EmployeePayslip): number {
  return report.payrolls?
    .reduce((prev, curr) => (prev.gross - prev.c_a - prev.statutory = prev.charges)   (curr.gross - curr.c_a - curr.statutory = curr.charges), 0);
}
Component TS
@Select(ReportState.getEmployeePayslipTotal) payslipTotal$: Observable<number>;
HTML
<div *ngIf="payslipTotal$ | async as payslipTotal">
  <p> {{ payslipTotal | number }} </p>
</div>

CodePudding user response:

You can't define functions in template. You can, however, use functions defined in component file, but this is not a good approach when it comes to change detection. That is well explained here: https://medium.com/showpad-engineering/why-you-should-never-use-function-calls-in-angular-template-expressions-e1a50f9c0496

I recommend 2 options:

1. create a 2nd observable, that depends on the first and can be also accessed via async pipe in template.

this.payrollSummary$: Observable<number> = this.report$.pipe(
  map(report => report?.payrolls?.reduce(/*...*/)),
);

2. pipe the value with a custom template pipe

<p>{{ report | payrollSummary }}</p>

@Pipe({
  name: 'payrollSummary',
})
export class PayrollSummaryPipe implements PipeTransform {
  transform(report: EmployeePayslip): number {
    return report?.payrolls?.reduce(/*...*/);
  }
}
  • Related