1

I would like how to know when a bonded property receives a value, even if it's the same value.

For example

That is a feature component

import {
    Component,
    OnInit,
    Input,
    OnChanges,
    SimpleChanges
} from '@angular/core';
@Component({
    selector: 'feature-component',
    templateUrl: './template.html',
    styleUrls: ['./style.sass'] 
}) 
export class FeatureComponent implements OnInit, Onchanges {

    @Input() bondedProperty: any;

    ngOnInit() {

    }

    ngOnChanges(simpleChanges: SimpleChanges) {
        // not called inside the setInterval function
        console.log('the bonded property received any value.');
    }

}

The component of the app

import {
    Component,
    AfterViewInit
} from '@angular/core';
@Component({
    selector: 'app-component',
    templateUrl: './template.html',
    styleUrls: ['./style.sass'] 
}) 
export class AppComponent implements AfterViewInit {

    bondedProperty: any;

    constructor() {
        this.bondedProperty = 10;
    }

    ngAfterViewInit() {
        const
            interval = setInterval(
                () => {
                    this.bondedProperty = 10;
                    console.log('function called after interval');
                    clearInterval(interval);
                }, 5000
            );
    }

}

And finally, the template of the app

<feature-component
    [bondedProperty]="bondedProperty"
>
</feature-component>

The problem is that if the same value is assigned in bondedProperty ngOnChanges isn't called, and the ngDoCheck method doesn't solve my problem because I would not know if the "change" was in bondedProperty.

rplaurindo
  • 1,277
  • 14
  • 23
  • 1
    You can use a setter and a getter on the bondedpropery – Hypenate Jan 06 '19 at 06:46
  • Using @ViewChild you can call child component method so that might help you – TheParam Jan 06 '19 at 06:48
  • There might me something similar to componentShouldUpdate like in Angular as in react.. where we got current state and new State of component – MukulSharma Jan 06 '19 at 14:53
  • Looks like some else is wrong in your project, created this [StackBlitz DEMO](https://stackblitz.com/edit/angular-so-54059234) and you can see that your code is working. – benshabatnoam Jan 06 '19 at 16:26
  • 2
    @benshabatnoam in your example you set the `bondedProperty` to a different value in `ngAfterViewInit` than in the constructor. It works with different values but not if the value is the same as the previously set value. – frido Jan 06 '19 at 18:00
  • @changulpaye how? Post a example about what do you want to say, please. – rplaurindo Jan 06 '19 at 18:53
  • 2
    @Hypenate setters work only if the attributed value is different. – rplaurindo Jan 06 '19 at 18:54

2 Answers2

0

As far as I know this can't be achieved with ngOnChanges or @Input setters as Angular is designed to only call ngOnChanges or the setter if the value actually changes.

If you want to detect new values even if they are the same as a previous value what you really want is probably to detect some kind of event. You could use an RxJS BehaviorSubject for that kind of purpose.

FeatureComponent

import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
import { BehaviorSubject }  from 'rxjs';
@Component({
    selector: 'feature-component',
    template: 'property: {{ bondedProperty$ | async }}',
    styleUrls: ['./style.sass'] 
}) 
export class FeatureComponent implements OnInit, Onchanges {

    @Input() bondedProperty$: BehaviorSubject<any>;

    ngOnInit() {
      this.bondedProperty$.subscribe(value => 
        console.log('the bonded property received any value.')
      );
    }

}

AppComponent

import { Component, AfterViewInit } from '@angular/core';
import { BehaviorSubject }  from 'rxjs';
@Component({
    selector: 'app-component',
    template: '<feature-component [bondedProperty$]="bondedProperty$"></feature-component>',
    styleUrls: ['./style.sass'] 
}) 
export class AppComponent implements AfterViewInit {

    bondedProperty$ = new BehaviorSubject<any>(0);

    constructor() {
        this.bondedProperty$.next(10);
    }

    ngAfterViewInit() {
        const
            interval = setInterval(
                () => {
                    this.bondedProperty$.next(10);
                    console.log('function called after interval');
                    clearInterval(interval);
                }, 5000
            );
    }

}

https://stackblitz.com/edit/angular-so-54059234-eshtnr

frido
  • 13,065
  • 5
  • 42
  • 56
  • Thanks. I know this solution, but I didn't want use it cause' my question is to be used in a external library, and this solution will require more complexity for the user. But if there is no other solution, will have to be that. – rplaurindo Jan 06 '19 at 19:01
  • @rplaurindo Well I guess you have to ask yourself why your feature component should care about an input property being set to the current value it already has. Your component doesn't need to be rendered again so Angular doesn't care about it. If you would state your actual use case people might be able to help you better. – frido Jan 06 '19 at 20:31
0

One simple way it to change your bondedProperty variable to be an object.

before:

this.bondedProperty = 10;

after:

this.bondedProperty = { 'value': 10 };

This way the change detection will catch your update event if the value in it is the same.

StackBlitz DEMO

benshabatnoam
  • 7,161
  • 1
  • 31
  • 52