1

You can see my Plunk here. In this very easy example I am passing a function

   _ => {
    console.log(number);
  }

to a child component with the @Input property. My parent component looks like that:

@Component({
    selector: 'my-app',
    template: `

                <child [func]="getFunction(3)">
                </child>
                <button type="button" (click)="startChangeDetection()">
                  Start change detection
                </button>
    `,
    directives : [Child],
    styles:[`

          .titles {
                    color:#0099FF
             }
            .child-style {
                    background-color:#00ffff
            }
            ` ],
})
export class CarComponent {
    startChangeDetection()
    {

    }
    getFunction(number)
    {
      return _ => {
        console.log(number);
      }
    }
}

The button does nothing else than trigger another round of change detection (there is no implementation in the callback function. However, my change detection always recognizes my input as a change, nevertheless it never changes. This is my child component:

@Component({
    selector: 'child',
    template: `
                <h2>Child Component</h2>
             `,
    inputs: ['func']
})
export class Child {

    private func;

    ngOnChanges(changes)
    {
      console.log(changes.func.previousValue.toString());
      console.log(changes.func.currentValue.toString());
    }

}

You can see, that in ngOnChanges I log my function to the console. But the logged value (obviously) does never change, so the output is always:

function (_) {
                        console.log(number);
                    }
function (_) {
                        console.log(number);
                    }

Why the heck does Angular even call ngOnChanges? And why does it think there is any change?

David
  • 1,275
  • 2
  • 17
  • 27
  • *“Why the heck does Angular even call ngOnChanges?”* – That part is somewhat simple: A DOM event triggers change detection on the `CarComponent` which causes the template to be reinterpreted and `getFunction(3)` is called again, which causes the value to change (to a different yet identical function) causing the `Child` component to update. That would be *if* the `Child` component had a `OnPush` change detection strategy; since it does not, change detection runs for it anyway (regardless of whether inputs changed). – poke Jan 23 '17 at 11:19
  • 1
    why you want to pass a function on input?? your concept is wrong and maybe you must think a different way to add value to your child component. let us know why and we can think a solution for you. – Odysseas Ioannou Jan 23 '17 at 11:23
  • Possible duplicate of [Angular2 pass callback function to child component as @Input](http://stackoverflow.com/questions/35328652/angular2-pass-callback-function-to-child-component-as-input) – poke Jan 23 '17 at 11:25
  • tl;dr: Use events/outputs instead. – poke Jan 23 '17 at 11:26

2 Answers2

3

This method returns a different function instance every time getFunction is called.

getFunction(number)
{
  return _ => {
    console.log(number);
  }
}

because of <child [func]="getFunction(3)">, getFunction is called every time change detection is run.

Binding to functions is usually not the best idea. If you move out the function creation this way, the same function instance is returned every time and Angular change detection won't recognize it as change:

myCallback = _ => this.myCallBack(number) {
  console.log(number);
}

getFunction(number)
{
  return this.myCallback;
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
1

I don't see anything abnormal there. The change detection is getting called twice.

  1. First time because child component is rendered inside car component. The component tree is changed.

  2. Second time because the function getFunction is getting called when you are passing it as getFunction(3) to the input. Thats equivalent to change in input value and hence triggering change detection cycle.

Santanu Biswas
  • 4,699
  • 2
  • 22
  • 21