I'm using angular, and in an angularUI modal window I want to show the Drop In form from Braintree to get a payment method. Thus, I create the usual form (partial.html
):
<form id="creditCard" >
<div id="dropin"></div>
<button type="submit" id="btnPay" >Pay</button>
</form>
and then I show the modal with this:
var modalInstance = $modal.open({
templateUrl: 'partial.html',
controller: 'ModalController'
});
Where ModalController contains the call to the Braintree setup:
braintree.setup($scope.clientToken, 'dropin', {
container: 'dropin',
onPaymentMethodReceived: function (result) {
$scope.$apply(function() {
$scope.success = true;
// Do something else with result
});
}
});
This will show the Drop In form from braintree nicely (the setup generates the form) and accept the credit card and expiration date, all working fine so far.
The problem is, each time I call the modal, the ModalController is executed, and thus the braintree.setup()
is also executed. Then, when I enter the credit card number and the expiration date and hit pay, the onPaymentMethodReceived()
event is triggered once per setup execution! That is, if the first time I call the modal it will trigger the event once, the second time it will trigger it twice, and so on. Like if each time I call setup, a new hook to the event is created.
Any idea on how to avoid this? Is there a way to "unbind" the onPaymentMethodReceived()
event handler? I do need to call the setup several times since each time I call the modal, the clientToken may have changed.
Thanks for any help or pointer to help.
Calling braintree.setup
multiple times in angular seems unavoidable, either for the asker's reasons, or simply because setup
is called in a controller that may be instantiated multiple times in a browsing session – like a cart or checkout controller.
You can do something like this:
$rootScope.success = false;
braintree.setup($scope.clientToken, 'dropin', {
container: 'dropin',
onPaymentMethodReceived: function (result) {
if(!$rootScope.success) {
$scope.$apply(function() {
$rootScope.success = true;
// Do something else with result
});
}
}
});
I found I wasn't able to avoid having the callback fire multiple times (the number of times seems to explode each time I revisit the view - yikes), but I could test whether I had performed my actions in response to the callback. Since the Because each new controller will have its own $scope
will be destroyed if I leave the view, $scope.success
is effectively reset when I need it to be.$scope
, setting a success
flag on the $scope
may only halt additional executions on that $scope
(which seems to still be available to the callback, even if the controller has been "destroyed"), so I found that using $rootScope
meant only one execution total, even if I re-instantiated the controller multiple times. Setting $rootScope.success = false
in the controller means that once the controller is loaded, the callback will succeed anew – once.
I think it's handled by the API since then with teardown:
In certain scenarios you may need to remove your braintree.js integration. This is common in single page applications, modal flows, and other situations where state management is a key factor. [...] Invoking teardown will clean up any DOM nodes, event handlers, popups and/or iframes that have been created by the integration.
https://developers.braintreepayments.com/guides/client-sdk/javascript/v2#teardown
(I haven't tried it yet)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With