Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 passing function as component input is not working

I've a component that takes function as input. I've passed this function from parent.

Though the function is called, the function is not able to access the dependencies of the instance on which this function is declared.

Here is the component

@Component({
  selector: 'custom-element',
  template: `
    {{val}}
  `
})
export class CustomElement {
  @Input() valFn: () => string;

  get val(): string {
    return this.valFn();
  }
}

Here is how the component is used

@Injectable()
export class CustomService {
  getVal(): string {
    return 'Hello world';
  }
}

@Component({
  selector: 'my-app',
  template: `
   <custom-element [valFn]="customVal"></custom-element>
  `,
})
export class App {
  constructor(private service: CustomService) {
  }
  customVal(): string {
    return this.service.getVal();
  }
}

When I run this app, I get an error in the console saying Cannot read property 'getVal' of undefined

Here is a plunker for the issue.

https://plnkr.co/edit/oQ229rXqOU9Zu1wQx18b?p=preview

like image 659
Ashok Koyi Avatar asked Mar 03 '17 09:03

Ashok Koyi


People also ask

Can we send function as input in Angular?

In your child component, add an @Input variable to bind the parent component's passed function: @Input() callbackFunction: (args: any) => void; Make sure that the signature definition of your @Input() function matches the myCallbackFunction that you defined in the parent component.

How to communicate between parent and child components in Angular?

@Input() and @Output() give a child component a way to communicate with its parent component. @Input() lets a parent component update data in the child component. Conversely, @Output() lets the child send data to a parent component.

How to use child component in parent component in Angular 9?

To let Angular know that a property in a child component or directive can receive its value from its parent component we must use the @Input() decorator in the said child. The @Input() decorator allows data to be input into the child component from a parent component.


2 Answers

You need to .bind(this) if you pass methods around:

<custom-element [valFn]="customVal.bind(this)"></custom-element>

or

export class App {
  constructor(private service: CustomService) {
  }
  customVal(): string {
    return this.service.getVal();
  }
  customValFn = this.customVal.bind(this);
}

with

<custom-element [valFn]="customValFn"></custom-element>
like image 142
Günter Zöchbauer Avatar answered Oct 12 '22 00:10

Günter Zöchbauer


You can pass a get/set property instead of a function in a similar way like that:

Somewhere in your view:

<input type="text" [(ngModel)]="yourprop">

In your component file:

@Component({
  selector: 'myapp',
  templateUrl: './myapp.component.html',
  styleUrls: ['./myapp.component.scss']
})
export class App {
  constructor() { }

  yourprop: any;

  get yourprop(): any {
    return this.scheduleEndDate;
  };

  //set accessor including call the onchange callback
  set yourprop(v: any) {
    // TODO do something else
    // You can do whatever you want just like you have passed a function

    if (v !== this.scheduleEndDate) {
      this.scheduleEndDate = v;
    }
  }

}

more info @ https://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel

like image 34
Combine Avatar answered Oct 12 '22 01:10

Combine