6

I'm trying to bind a function in a parent component into a property on a child component.

This is what I have

@Component({
  selector: 'awesome',
  templateUrl: 'awesome.html'
})
export class AwesomeComponent {

@Input() callback: Function;

ngOnInit() {

    this.callback();//Error, this.callback is not a function,  but contains a string value on the fuction call
    }
}

This is how i'm using it

<awesome callback="nameOfFuncFromAnotherComponent"></awesome>

but it doesn't seem to work

4 Answers 4

8

Your code only binds the string nameOfFuncFromAnotherComponent to the callback attribute (and property if it exists). Angular doesn't interpret the value at all.

To make Angular manage the binding use

<awesome [callback]="nameOfFuncFromAnotherComponent"></awesome>

With this syntax Angular also evaluates the value

<awesome callback="{{nameOfFuncFromAnotherComponent}}"></awesome>

but converts the result to a string (calls .toString()) before the assignment.

Thanks to @MarkRajcok for clarification :)

Sign up to request clarification or add additional context in comments.

5 Comments

Since component awesome has a callback input property declared, callback="nameOfFuncFromAnotherComponent" will bind the string nameOfFuncFromAnotherComponent to the callback property of the component (not the attribute). This is some sort of Angular shortcut/special syntax for constants (that I don't like).
@StevenYates, callback="{{nameOfFuncFromAnotherComponent}}" won't work because it essentially calls nameOfFuncFromAnotherComponent.toString() and assigns that to the callback property. {{}} binding always assigns a string result.
@MarkRajcok thanks a lot for your insightful explanations!
How to do if the function has parameters?
There is no difference. The difference is when you later call the function, then you have to pass parameters. Here only a reference to the function is passed.
7

i think using eventEmitter in the case of function is much more better becouse of the passing the function by reference will make some problems with the this

so my suggestion is to do the following

cm1.component.html

<cm2-component (childFunc)="myFunc()"></cm2-component>

cm2.component.ts

import { Output, EventEmitter } from '@angular/core';
export class Cm2 {
  @Output('childFunc') childFunc: EventEmitter<any> = new EventEmitter();
  constructor() { }
  invokeMyFunc(){
    this.childFunc.emit()
  }
}

1 Comment

I also like the eventEmitter approach. I had a problem with this too but it can be overcome by turning a parent function into a delegate.
1

There is really no need for pushing callback into @Input property. You can use #local_variable wich provides a reference to the child component. That way you will have access to all its properties and methods from the parent template. See ng2 documentation on component interaction.

1 Comment

if I'm not mistaken, he's looking for the opposite communication flow where the child component calls a method of the parent. So, the parent passes its function to the child.
1

For me this solution worked:

Template

<cm2-component [childFunc]="myFunc.bind(this)"></cm2-component>`

Component

import { Output, EventEmitter } from '@angular/core';
export class Cm2 {
  @Input('childFunc') childFunc: Function;
  constructor() { }
  invokeMyFunc(){
    this.childFunc()
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.