Hassan Hassan - 2 months ago 29
TypeScript Question

how to trigger change with @input decorator angular 2

I have a parent component which has a

title
field. This field is passed to the child component using the
@input
decorator. In my child component i have added some logic to manipulate the
title
value before showing it in my HTML.

Because my logic is in
ngInit
hook of the child component, only the first time the
title
field is reflected correctly. Changes that happen from then onwards do not reflect. Now i know this is because
ngInit
is called once but how do i trigger a change from my parent to child telling it to recheck the value?

EDIT Added code snippet

Header (child) component

export class HeaderComponent implements OnInit {
@Input() title: string | Array<any>;

titleType = 'string';
tabletTitle: string | Array<any>;


constructor() { }

ngOnInit() {

if ( typeof this.title == 'object' ) {
this.titleType = 'array';

// For tablet - only send the last most array item
this.tabletTitle = [this.title[this.title.length - 1]]; // Has to be in the form of array (to be consistent with other orange header data type)
} else {
// Title is string - same for tablet
this.tabletTitle = this.title;
}

// Temporary to show filter button on catalog page
if ( this.page == 'catalog' ) {
this.showFilterButton = true;
}
}
}


Header template

<h1 *ngIf="titleType=='string'">{{title}}</h1>
<h1 *ngIf="titleType=='array'">
<ul class="header-breadcrumb">
<template ngFor let-item [ngForOf]="title | keyValueObject">
<li title="{{item.value['title']}}">
<a *ngIf="item.value['link']" [routerLink]="item.value['link']">{{item.value['title']}}</a>
<span *ngIf="!item.value['link']">{{item.value['title']}}</span>
</li>
<li *ngIf="!last" class="separator"></li>
</template>
</ul>
<ul class="header-breadcrumb tablet">
<li *ngFor="let item of tabletTitle | keyValueObject">
<a *ngIf="item.value['link']" [routerLink]="item.value['link']">{{item.value['title']}}</a>
<span *ngIf="!item.value['link']">{{item.value['title']}}</span>
</li>
</ul>
</h1>


Parent component

if ( this.parentCatId ) {
// Push Parent Category name in header title
this.headerTitle.push({title: 'Parent'});
}

if ( this.subCatId ) {
// Push Sub Category name in header title
this.headerTitle.push({title: 'Child'});
}


Parent component HTML

<app-header [title]="headerTitle"></app-header>

Answer

You can either make @Input() title: string | Array<any> a setter or use ngOnChanges() instead of ngOnInit(). ngOnChanges() is called every time an @Input() is updated.

@Input() set title(value: string | Array<any>) {
  ...
}

or

ngOnChanges() {

    if ( typeof this.title == 'object' ) {
        this.titleType = 'array';

        // For tablet - only send the last most array item
        this.tabletTitle = [this.title[this.title.length - 1]];     // Has to be in the form of array (to be consistent with other orange header data type)
    } else {
        // Title is string - same for tablet
        this.tabletTitle = this.title;
    }

    // Temporary to show filter button on catalog page
    if ( this.page == 'catalog' ) {
        this.showFilterButton = true;
    }
}
Comments