Reputation: 745
I want to pass a function that has an http request from a parent component to a child component, and from the child component execute the request.
My code as the following:
// myService
constructor(private http: HttpClient)
getIds(id) {
// return of(['a', 'b', 'c', id]); with this works
return this.http.get(apiUrl) // with this doesnt work
}
// parentComponent.ts
callbackFunction = this.myService.getIds;
constructor(private myService: MyService) { }
// parentComponent.html
<child-component [callbackRequest]="callbackFunction"></child-component>
// childComponent.ts
@Input() callbackRequest;
ngOnInit() {
this.callbackRequest('d');
}
What confuses me the most is that if from the service I return an observable built from of, if it works. When debugging I see that if the call to the service arrives. The error I get is the following: ERROR TypeError: Cannot read property 'get' of undefined
Upvotes: 0
Views: 784
Reputation: 1847
Is there a specific reason to work with a callback function?
Normaly i would try to make one component "smart" and one "dumb".
In your case the parent is the one which decides WHAT to do (which HTTP request) and the child decides WHEN to do it. And perhaps the child also should show the result.
Therefore i decided in a similar case, that my child will inform the parent when its time to run the request, then the parent runs the request and provides the result to the child.
Yes, that way i need not just one INPUT, but one INPUT and an OUTPUT for my child. On the other side, my child has a cleanly defined INPUT interface. If i just provide a callback method, the call back may return anything.
Also my child has nearly no "logic" in it. All the magic is in the parent. That makes it quite easy to write UnitTests for the child component. And also for the parent its quite easy with just a mocked child.
Yes, JavaScript (and therefore also TypeScript) allow things like .bind()
. But in my experience it seems to solve a problem quite fast, but the real effort comes later. Its harder to understand and its harder to debug. Therefore i normaly avoid it.
Just another way to solve a problem. Pick the parts you like and igore the rest :- )
Upvotes: 0
Reputation: 31115
The meaning of this
keyword inside the getIds
function is lost when it's reference is passed around using the @Input
binding in Angular. It works when you return of([...])
because there is no usage of this
. See here for a canonical post on the meaning of this
keyword in a callback
There are two solutions
bind
- see the post from @GabrielSerenoService
public getIds = (id) => {
return this.http.get(apiUrl);
}
Component
callbackFunction: any;;
constructor(private myService: MyService) { }
ngOnInit() {
this.callbackFunction = this.myService.getIds;
}
Template
<ng-container *ngIf="callbackFunction">
<child-component [callbackRequest]="callbackFunction"></child-component>
</ng-container>
Upvotes: 1
Reputation: 855
You can do it:
// myService
constructor(private http: HttpClient)
getIds(id) {
// return of(['a', 'b', 'c', id]); with this works
return this.http.get(apiUrl) // with this doesnt work
}
// parentComponent.ts
callbackFunction = this.myService.getIds.bind(this.myService);
constructor(private myService: MyService) { }
// parentComponent.html
<child-component [callbackRequest]="callbackFunction"></child-component>
// childComponent.ts
@Input() callbackRequest;
ngOnInit() {
this.callbackRequest('d');
}
.bind(this) is the solution, because the function will be able to use the parent instance (you can see that everything turn undefined when you don't bind it)
Upvotes: 1