обратный вызов jQuery вызывается дважды - PullRequest
2 голосов
/ 04 февраля 2012

Я следую за кастом Rails для реализации биллинга по подписке. Это здесь:

http://railscasts.com/episodes/288-billing-with-stripe

Мой код практически идентичен, хотя я передаю некоторые дополнительные поля в Stripe. Проблема в том, что сообщение об ошибке в javascript ВСЕГДА отображает сообщение об ошибке, когда нажимается кнопка отправки ... даже при успешных расходах. Я не уверен, что Strip возвращает что-то, что вызывает ошибку, или есть проблема с JS.

jQuery ->
  Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'))
  subscription.setupForm()

subscription =
  setupForm: ->
    $('#new_membership').submit ->
      $('input[type=submit]').attr('disabled', true)
      if $('#card_number').length
        subscription.processCard()
        false
      else
        true

  processCard: ->
    card =
      number: $('#card_number').val()
      cvc: $('#card_code').val()
      expMonth: $('#card_month').val()
      expYear: $('#card_year').val()
    Stripe.createToken(card, subscription.handleStripeResponse)

  handleStripeResponse: (status, response) ->
    if status == 200
      $('#membership_stripe_card_token').val(response.id)
      $('#new_membership')[0].submit()
    else
      $('#stripe_error').text(response.error.message)
      $('input[type=submit]').attr('disabled', false)

Это пример, который полоса дает для обработки ошибок. Они переворачивают процесс и сначала проверяют на ошибки:

function stripeResponseHandler(status, response) {
    if (response.error) {
        ...
        //show the errors on the form
        $(".payment-errors").html(response.error.message);
    } else {
        var form$ = $("#payment-form");
        // token contains id, last4, and card type
        var token = response['id'];
        // insert the token into the form so it gets submitted to the server
        form$.append("<input type='hidden' name='stripeToken' value='" + token + "'/>");
        // and submit
        form$.get(0).submit();
    }
}

ОБНОВЛЕНИЕ: Итак, я могу рассказать вам, что происходит, но не совсем, почему или как это исправить.

Я добавил оператор журнала консоли и теперь вижу, что handleStripeResponse вызывается дважды, один раз, когда пользователь нажимает на submit, и он возвращает 200, затем кажется снова (возможно, потому что форма должна отправлено в приложение Rails для фактической обработки? и он возвращает 0, который выдает сообщение об ошибке. НО - поскольку Rails теперь обрабатывает серверную часть обработки, плата проходит.

Вот скомпилированный JS, если это поможет:

(function() {
  var subscription;

  jQuery(function() {
    Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));
    return subscription.setupForm();
  });

  subscription = {
    setupForm: function() {
      return $('#new_membership').submit(function() {
        $('input[type=submit]').attr('disabled', true);
        if ($('#card_number').length) {
          subscription.processCard();
          return false;
        } else {
          return true;
        }
      });
    },
    processCard: function() {
      var card;
      card = {
        number: $('#card_number').val(),
        cvc: $('#card_code').val(),
        expMonth: $('#card_month').val(),
        expYear: $('#card_year').val()
      };
      return Stripe.createToken(card, subscription.handleStripeResponse);
    },
    handleStripeResponse: function(status, response) {
      if (status === 200) {
        $('#membership_stripe_card_token').val(response.id);
        return $('#new_membership')[0].submit();
      } else {
        $('#stripe_error').text(response.error.message);
        return $('input[type=submit]').attr('disabled', false);
      }
    }
  };

}).call(this);

Ответы [ 6 ]

5 голосов
/ 04 января 2013

У меня была такая же проблема.Я неосознанно вызывал javascript дважды.

Один раз (явно) на странице:

= javascript_include_tag 'stripe'

И затем снова (непреднамеренно) в приложении.1008 * В результате функция готовности документа jQuery вызывается дважды, что приводит к двойной настройке всех слушателей.

В зависимости от того, как настроены ваши приложения, вам следует избавиться от одного или другого включения.Для моего приложения лучше всего было удалить строку из моего application.js.

Хитрый конвейер активов!

1 голос
/ 22 февраля 2015

Была такая же проблема.Просто вытащил jQuery -> из верхней части файла coffeescript, в котором хранился код Stripe, и двойная передача прекратилась.Получил подсказку от Натана Колгейта выше.

0 голосов
/ 18 декабря 2018

Итак, сегодня на работе у нас была похожая проблема:

  • Использование Rails 4.2
  • Использование формы ajax (remote = true) со встроенным скриптом jquery-ujs.js, поставляемым с Rails
  • Использование Stripe в качестве платежного шлюза (они предоставляют скрипт, который через iframe обрабатывает некоторую информацию о кредитной карте)
  • При отправке нашей формы (с настраиваемой логикой ajax) она отправляет форму дважды, один раз для обработчика отправки формы глобального события Ruby и один раз для "нашего настраиваемого" обработчика события

Stripe хочет сначала обработать отправку формы, отправив ajax'у в собственный домен Stripe, и когда результат вернется, он хочет заполнить некоторые скрытые поля в форме их ответными данными. После этого Stripe хочет, чтобы мы отправили форму как обычно.

Для нас был конфликт в том, что как Rails, так и Stripe реагировали на отправку формы и не координировали. Так как мы не можем легко изменить jquery-ujs.js, мы изучили, как они закодировали свой глобальный обработчик события "submit" формы.

Оказывается, объект rails представлен как плагин jQuery, в котором есть функция, препятствующая обработчику jquery-ujs.js обрабатывать любое событие - аккуратно!

Так что нам нужно было позвонить ...

 $.rails.stopEverything(event);

... внутри обработчика событий отправки Stripe (это особый случай для нашего проекта)

Вот код для обработчика событий Stripe для дополнительного контекста:

// Create a token or display an error when the form is submitted.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function (event)
{
    $.rails.stopEverything(event); // Dont let Rails' global form submit handler handle this event (in jquery-ujs.js)
    event.preventDefault();

    stripe.createToken(card).then(function(result)
    {
        if (result.error)
        {
            // Inform the user if there was an error
            var errorElement = document.getElementById('card-errors');
            errorElement.textContent = result.error.message;
            $('#stripe-btn').prop('disabled', false)
            $('.fa-spin').remove()
        }
        else
        {
            // Send the token to your server
            stripeTokenHandler(result.token);
        }
    });
});
0 голосов
/ 09 октября 2015

Для тех, кто читает это: если у вас возникла подобная проблема, я рекомендую взглянуть на «Просмотр исходного кода» или эквивалентную информацию, чтобы увидеть, включены ли некоторые javascript-коды дважды.

Iследовал тому же Railscast и столкнулся с той же проблемой.Это заняло у меня больше времени, чем я могу себе представить, но моей проблемой было копирование, вставляя строку из заметок на железной дороге, пока я спал.Причиной было то, что javascript-коды приложения были включены дважды, один раз с автоматически сгенерированными рельсами, включенными в application.html.erb:

<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>

и второй раз, вставив строку из заметок Railscast:

<%= javascript_include_tag "https://js.stripe.com/v1/", "application" %>

, следовательно, включая «приложение» дважды.Я решил это, просто удалив один из них.

0 голосов
/ 15 марта 2012

У меня возникла такая же проблема.Все еще не уверен, что вызвало это.Решение, которое я нашел, состояло в том, чтобы добавить другую проверку в coffeescript:

subscription =
  setupForm: ->
    $('#new_subscription').submit ->
      $('input[type=submit]').attr('disabled', true)
      if $('#subscription_stripe_card_token').val
        true
      else
        subscription.processCard()
        false

Обратите внимание, что вместо оператора if вместо проверки:

if $('#card_number').length

вместо этого я поставил проверкуfor:

if $('#subscription_stripe_card_token').val

Таким образом, когда форма отправляется в первый раз, она успешно возвращает значение для stripe_card_token и, следовательно, не будет отправлять форму во второй раз.Чего я пока не знаю, так это того, что использование метода card_number.length из railscast не работало.Я полагаю, что это может быть что-то не так с объектом @subscription, который не распознает, что теперь он имеет значение для stripe_card_token, и поэтому не удаляет поле card_number ... но я не знаюпомогает приблизиться к окончательному ответу здесь!

0 голосов
/ 04 февраля 2012

Итак, мое хакерское решение до сих пор состоит в том, чтобы сделать это, так как во второй раз при обратном вызове он последовательно возвращает 0.

 else if status == 0
      $('#stripe_error').text('Processing...')

По крайней мере, таким образом, пользователь не получает сообщение об ошибке, и кнопка отправки не активируется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...