Множественная настройка Braintree вызывает выход в нескольких событиях onPaymentMethodReceived

Я использую angular, и в модальном окне angularUI я хочу показать форму Drop In из Braintree, чтобы получить способ оплаты. Таким образом, я создаю обычную форму (partial.html):

<form id="creditCard" >
   <div id="dropin"></div>  
   <button type="submit" id="btnPay" >Pay</button>  
</form>

а затем я покажу modal с этим:

var modalInstance = $modal.open({
   templateUrl: 'partial.html',
   controller: 'ModalController'
});

Где ModalController содержит вызов установки Braintree:

braintree.setup($scope.clientToken, 'dropin', {
   container: 'dropin',
   onPaymentMethodReceived: function (result) {
       $scope.$apply(function() {
           $scope.success = true;
           // Do something else with result
       });
   }
});

Это будет хорошо отображать форму Drop In от braintree (настройка генерирует форму) и принять кредитную карту и дату истечения срока действия, все работает до сих пор.

Проблема заключается в том, что каждый раз, когда я вызываю модальный, выполняется ModalController, и, таким образом, выполняется также braintree.setup(). Затем, когда я ввожу номер кредитной карты, дату истечения срока действия и выигрыш, событие onPaymentMethodReceived() запускается один раз при выполнении установки! То есть, если в первый раз, когда я вызову модальный, он вызовет событие один раз, второй раз он вызовет его дважды и так далее. Как если бы каждый раз, когда я вызываю настройку, создается новый крючок для события.

Любая идея о том, как этого избежать? Есть ли способ "отвязать" обработчик события onPaymentMethodReceived()? Мне нужно вызвать установку несколько раз, так как каждый раз, когда я вызываю модальный, клиентToken, возможно, изменился.

Спасибо за помощь или указатель.

Ответ 1

Вызов braintree.setup несколько раз в angular кажется неизбежным, как по причинам, указанным в опросе, так и просто потому, что setup вызывается в контроллере, который может быть запущен несколько раз в сеансе просмотра - например, в тележке или контролере.

Вы можете сделать что-то вроде этого:

$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
           });
       }
   }
});

Я обнаружил, что не мог избежать многократного обратного вызова (количество раз, кажется, взорвалось каждый раз, когда я возвращался к просмотру - yikes), но я мог проверить, выполнил ли я свои действия в ответ на Перезвони. Поскольку $scope будет уничтожен, если я оставлю представление, $scope.success будет эффективно reset, когда мне это понадобится. Поскольку каждый новый контроллер будет иметь свой собственный $scope, установка Флаг success на $scope может останавливать дополнительные исполнения на этом $scope (который, кажется, все еще доступен для обратного вызова, даже если контроллер был "уничтожен" ), поэтому я обнаружил, что использование $rootScope означает только одно исполнение, даже если я повторно создавал экземпляр контроллера несколько раз. Установка $rootScope.success = false в контроллере означает, что после загрузки контроллера обратный вызов будет выполнен заново - один раз.

Ответ 2

Я думаю, что он обрабатывается API с тех пор с помощью teardown:

В некоторых сценариях вам может потребоваться удалить вашу интеграцию с braintree.js. Это распространено в приложениях с одной страницей, модальных потоках и других ситуациях, когда управление состоянием является ключевым фактором. [...] Вызов teardown очистит любые узлы DOM, обработчики событий, всплывающие окна и/или iframes, созданные с помощью интеграции.

https://developers.braintreepayments.com/guides/client-sdk/javascript/v2#teardown

(я еще не пробовал)

Ответ 3

Ссылка, предоставленная Arpad Tamas, больше не содержит информации. Поэтому я публикую информацию, данную BrainTree для потомков;) Тем более, что мне потребовалось несколько попыток найти ее с помощью поиска Google.

В некоторых сценариях вам может потребоваться удалить вашу интеграцию с Braintree.js. Это распространено в приложениях с одной страницей, модальных потоках и других ситуациях, когда управление состоянием является ключевым фактором. При вызове функции braintree.setup вы можете присоединить обратный вызов к onReady, который предоставит объект, содержащий метод teardown.

Вызов teardown очистит любые узлы DOM, обработчики событий, всплывающие окна и/или iframes, созданные при интеграции. Кроме того, разрывы принимают обратный вызов, который вы можете использовать, чтобы знать, когда это безопасно.

var checkout;

braintree.setup('CLIENT_TOKEN_FROM_SERVER', 'dropin', {
  onReady: function (integration) {
    checkout = integration;
  }
});

// When you are ready to tear down your integration
checkout.teardown(function () {
  checkout = null;
  // braintree.setup can safely be run again!
});

Вы можете вызывать только разрывы раз за один вызов .setup. Если вам посчастливилось вызвать этот метод, пока идет другое разрывание, вы получите сообщение об ошибке. Не удается вызвать прерывание во время выполнения. После завершения последующие вызовы к разрыву будут вызывать ошибку с этим сообщением: Невозможно отключить интеграцию более одного раза.

Я завернул этот код в функцию, которую я вызываю каждый раз, когда вводится соответствующий контрольный ионный вид.

$scope.$on('$ionicView.enter', function() {
    ctrl.setBraintree(CLIENT_TOKEN_FROM_SERVER);
});

var checkout;

ctrl.setBrainTree = function (token) {
    braintree.setup(token, "dropin", {
        container: "dropin-container",

        onReady: function (integration) {
            checkout = integration;
            $scope.$emit('BTReady');
        },

        onPaymentMethodReceived: function(result) {
            ...
        },

        onError: function(type) {
            ...
        }
    });

    // Prevents a call to checkout when entering the view for the first time (not initialized yet).
    if (checkout) {
    // When you are ready to tear down your integration
        checkout.teardown(function () {
            checkout = null; // braintree.setup can safely be run again!
        });
    }
};