Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6: Function call within HTML interpolation returns undefined

I'm attempting to call a function inside my HTML interpolation, like so. This HTML chunk is inside a *ngFor loop.

<mat-list>
    <mat-list-item *ngFor="let unit of units">
    <div>
        <p>Remaining Life</p>
        <h2>{{ parseTimeRemaining(unit.daysRemaining) }}</h2>
    </div>
    </mat-list-item>
<mat-list>

parseTimeRemaining() returns a string to be displayed, using the value of unit.daysRemaining as a parameter.

public parseTimeRemaining(days: number){
    const timeString = days + " Days";
    return timeString;
}

Currently, my function returns undefined and thus, an empty <h2> element. Did I do something wrong? If so, what's the best way to display the information I need?

like image 732
Hamadyne Avatar asked Sep 06 '25 09:09

Hamadyne


1 Answers

This could be a great opportunity to use a Pipe instead of a function. This helps to avoid calling a function within an *ngFor which can have detrimental affects to performance. From the documentation surrounding pipes and change detection.

Angular picks a simpler, faster change detection algorithm when you use a pipe.

Angular has a built-in pipe, I18nPluralPipe which "Maps a value to a string that pluralizes the value according to locale rules.". You create an object (pluralMap) targeting specific numerical values and indicate the resulting string should be allowing to say 0 Days, 1 Day, or 99 days.

pluralMap = {
  '=0': '0 Days',
  '=1': '1 Day',
  'other': '# Days'
};

You would use it in a template as follows:

<ul>
  <li *ngFor="let unit of units">{{ unit.daysRemaining | i18nPlural:pluralMap }}</li>
</ul>

Another approach would be to create a Custom Pipe. This would allow you implement custom formatting and/or validation logic against the provided daysRemaining.

Pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'daysRemaining'})
export class DaysRemainingPipe implements PipeTransform {
  transform(days: number): string {
    const timeString = days + " Days";
    return timeString;
  }
}

Module (registration):

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; 
import { AppComponent } from './app.component';
import { DaysRemainingPipe } from './days-remaining.pipe';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, DaysRemainingPipe ]
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

Template:

<ul>
  <li *ngFor="let unit of units">{{ unit.daysRemaining | daysRemaining }}</li>
</ul>

Taking it one step further, we could extend the I18nPluralPipe to pluralize the results within our custom pipe by extending the built in pipe and maybe check if the input is a valid number.

import { Pipe, PipeTransform } from '@angular/core';
import { I18nPluralPipe } from '@angular/common';

@Pipe({name: 'daysRemaining'})
export class DaysRemainingPipe extends I18nPluralPipe implements PipeTransform {
  transform(days: number): string {
    const safeDays = isNaN(days) ? 0 : days;

    const pluralMap = {
      '=0': '0 Days',
      '=1': '1 Day',
      'other': '# Days'
    };

    return super.transform(safeDays, pluralMap);
  }
}

Here is an example in action.

Hopefully that helps!

like image 194
Alexander Staroselsky Avatar answered Sep 08 '25 06:09

Alexander Staroselsky