Reputation: 151
in my Angular 5 project I have some problems with the callback from an external library. I load it using
<script src="https://js.chargebee.com/v2/chargebee.js" data-cb-site="my-site"> </script>
and then in Angular I import it as follows:
declare var Chargebee: any;
Chargebee.init({site: "my-site"});
I also have a public variable in my component, lets say publicVar
, which I am displaying in the template.
publicVar: string = 'before checkout';
I have the following method:
subscribeToPlan() {
var _self = this;
var chargebeeInstance = Chargebee.getInstance();
chargebeeInstance.openCheckout({
hostedPage: function() {
_self.publicVar = 'hosted-page';
console.log('hosted-page');
},
success: function(hostedPageId) {
_self.publicVar = 'success';
console.log('success');
},
close: function() {
_self.publicVar = 'closed';
console.log('closed');
}
});
}
What is happening when I run the code?
All the console.log
functions output the correct data, so I know the chargebee callbacks are called. However, only hostedPage: function() {}
correctly changes my publicVar
, and it says "hosted-page" in my template.
success: function(){}
nor close: function(){}
won't update the publicVar
in my template. I suspect because these are, unlike the hostedPage
, a callback methods and the self.
in them has wrong context?
Upvotes: 3
Views: 3133
Reputation: 151
So I worked it out (or found a workaround)
As the _self
did hold the correct data, I thought that the change detection is not triggered for those callbacks. After I've manually triggered it, it all works as expected.
Final code and changes:
Import
import { ChangeDetectorRef } from '@angular/core';
Add it to the constructor:
constructor(private cd: ChangeDetectorRef)
And then call it at the end of the callback method, this will manually trigger Angular change detection, and updates template rendering of publicVar
subscribeToPlan() {
var _self = this;
var chargebeeInstance = Chargebee.getInstance();
chargebeeInstance.openCheckout({
hostedPage: function() {
_self.publicVar = 'hosted-page'; // This is not a callback, so it just works
console.log('hosted-page');
},
success: function(hostedPageId) {
console.log('success');
_self.publicVar = 'success';
_self.cd.detectChanges(); // Manual change detection
},
close: function() {
console.log('closed');
_self.publicVar = 'closed';
_self.cd.detectChanges(); // Manual change detection
}
});
}
Alternative code using the arrow functions, as per Joe's suggestion (https://stackoverflow.com/a/50335020/5644425)
subscribeToPlan() {
var chargebeeInstance = Chargebee.getInstance();
chargebeeInstance.openCheckout({
hostedPage: () => {
this.publicVar = 'hosted-page';
console.log('hosted-page');
},
success: hostedPageId => {
console.log('success');
this.publicVar = 'success';
this.cd.detectChanges();
},
close: () => {
console.log('closed');
this.publicVar = 'closed';
this.cd.detectChanges();
}
});
}
Upvotes: 2
Reputation: 7004
Rather than assigning this to some variable _self
you could just use arrow functions, which don't affect the scope of this
:
subscribeToPlan() {
var chargebeeInstance = Chargebee.getInstance();
chargebeeInstance.openCheckout({
hostedPage: () => {
this.publicVar = 'hosted-page';
console.log('hosted-page');
},
success: hostedPageId => {
this.publicVar = 'success';
console.log('success');
},
close: () => {
this.publicVar = 'closed';
console.log('closed');
}
});
}
And without the logging this becomes the even neater:
subscribeToPlan() {
var chargebeeInstance = Chargebee.getInstance();
chargebeeInstance.openCheckout({
hostedPage: () => this.publicVar = 'hosted-page',
success: hostedPageId => this.publicVar = 'success',
close: () => this.publicVar = 'closed'
});
}
Though I think your code should work fine. You're assigning this
to _self
and using that, so the this
of the functions shouldn't matter. I'd definitely recommend putting in a breakpoint and checking what _self
is in those two functions.
Upvotes: 1