在我的结帐中实施了 Stripe v3 卡片元素,并且 jquery 停止工作

Posted

技术标签:

【中文标题】在我的结帐中实施了 Stripe v3 卡片元素,并且 jquery 停止工作【英文标题】:Implemented Stripe v3 card element in my checkout and jquery stopped working 【发布时间】:2020-11-15 13:57:43 【问题描述】:

我最近开始在结帐表单中切换到使用条纹卡元素,并且我已经让条纹元素正确显示在页面上,但我注意到,当我开始使用它时,现在我所有的 Jquery 调用都在该表单上停止工作。这与条纹有关吗?我想知道注入卡片元素的 Stripe 是否会阻止文档使用 Jquery 触发“就绪”状态。我的代码在下面,我真的可以对此有所了解,因为我已经达到了对此的了解,并且似乎无法找到一种方法来完成这项工作。 (注意:我正在使用 jquery 来更新通过用户填写的表单版本的表单上的隐藏字段,一个表单有两个附加字段。页面上的 Jquery 还会动态更新屏幕上显示的“总计” . 实际总数使用相同的函数输入,但在后端验证后调用。)

这是我的 _order_form.html.erb

<script src="https://js.stripe.com/v3/"></script>


<div class="row">
    <div class="col-md-9 mb-md-0 mb-5">
        <%= form_for @order do |f| %>

           
        <%= f.hidden_field 'referred_by_school',  id: "referBySchool"  %>

           <div class="row">
                <div class="col-md-6">
                    <div class="md-form mb-0">
                        <%= f.label :customer_name, "Your Name *", class: "control-label" %><br />
                        <%= f.text_field :customer_name, class: "form-control" %>
                    </div>
                </div>

                <div class="col-md-6">
                    <div class="md-form mb-0">
                        <%= f.label :email, "Email *", class: "control-label" %><br />
                        <%= f.text_field :email, class: "form-control" %>
                    </div>
                </div>
           </div>
        <% if locals[:buy_method] == "group"%>

            <div class="row">
                <div class="col-md-6">
                    <div class="md-form mb-0">
                        <%= f.label :student_name, "Student Name *", class: "control-label" %><br />
                        <%= f.text_field :student_name, class: "form-control" %>
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="md-form mb-0">
                        <%= f.label :school_name, "School or Group Name *", class: "control-label" %><br />
                        <%= f.text_field :school_name, class: "form-control"%>
                    </div>
                </div>
            </div>

        <br>
        
        <% end %>
        <div class="col-md-2">Shipping Info</div>
    
            <div class="col-md-6">
            
                <div class="shipping-container">
                    <div class="row">
                            <div class="col-md-12">
                                <div class="md-form mb-0">
                                    <%= f.label :street_address, "Street Address *", class: "control-label" %><br />
                                    <%= f.text_field :street_address, class: "form-control" %>
                                </div>
                            </div>
                    </div>

                    <div class="row">
                        <div class="col-md-4">
                            <div class="md-form mb-0">
                                <%= f.label :city, "City *", class: "control-label" %><br />
                                <%= f.text_field :city, class: "form-control" %>
                            </div>
                        </div>

                        <div class="col-md-3">
                            <div class="md-form mb-0">
                                <%= f.label :state, "State *", class: "control-label" %><br />
                                <%= f.select :state, ['AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FM', 'FL', 'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MH', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PW', 'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VI', 'VA', 'WA', 'WV', 'WI', 'WY' ], class: "form-control"%>
                            </div>
                        </div>

                        <div class="col-md-4">
                            <div class="md-form mb-0">
                                <%= f.label :zip_code, "Zip code *", class: "control-label" %><br />
                                <%= f.text_field :zip_code, class: "form-control" %>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <br>

            <div class="row">
                <div class="col-md-6">
                    <div class="md-form mb-0">
                        <%= f.check_box :email_permission, checked: "checked", checked_value: true, unchecked_value: false %>
                        <%= f.label :email_permission, class: "checkbox-inline", class: "control-label" %>
                    </div>
                </div>
           </div>

           <br>

            <div class="row">
                <div class="col-md-6">
                    <div class="md-form mb-0">
                        <%= f.label :number_books, value: "Number of books to purchase *", class: "control-label" %><br />
                        <% if locals[:buy_method] == "group" %>
                            <%= f.text_field :number_books, class: "form-control", id: "groupNumberBooks" %>
                        <% elsif locals[:buy_method] == "individual" %>
                            <%= f.text_field :number_books, class: "form-control", id: "individualNumberBooks" %>
                        <% end %>
                    </div>
                </div>
            </div>

            <% if locals[:buy_method] == "group" %>
                <div class="col-md-2">
                    <div class="row">
                        <%= f.label :total, value: "Total: $", class: "control-label" %>
                    </div>

                    <div class="row">
                        <%= f.label :total, id: "groupTotal", class: "form-control", value: 0 %>  
                    </div>
                </div>
            <% end %>

            <% if locals[:buy_method] == "group" %>
                <div class="row" id="card_field1">
                    <div class="col-md-6">
                        <div id="card-element-1"><!--Stripe.js injects the Card Element--></div>
                            <button id="submit-1">
                                <div class="spinner hidden" id="spinner"></div>
                                <span id="button-text">Pay</span>
                            </button>
                            <p id="card-errors-1" role="alert"></p>
                    </div>
                </div>
            <% end %>

            <% if locals[:buy_method] == "individual" %>
                <div class="row">
                    
                    <div class="form-group">
                        <%= f.label :total, value: "Total: $", class: "control-label" %> <br>
                        <%= f.label :total, id: "individualTotal", class: "form-control", value: 0 %>
                    </div>
                    
                </div>
            <% end %>

            <% if locals[:buy_method] == "individual" %>
                <div class="row" id="card_field2">
                    <div class="col-md-6">
                        <div id="card-element-2"><!--Stripe.js injects the Card Element--></div>
                            <button id="submit-2">
                                <div class="spinner hidden" id="spinner"></div>
                                <span id="button-text">Pay</span>
                            </button>
                            <p id="card-errors-2" role="alert"></p>
                    </div>
                </div>
            <% end %>
            
        
               
        <% end %>
    </div>
</div>

<script>
// Create a Stripe client.
var stripe = Stripe('pk_test_***************************************');

// Create an instance of Elements.
var elements1 = stripe.elements();
var elements2 = stripe.elements();

// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = 
  base: 
    color: '#32325d',
    fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
    fontSmoothing: 'antialiased',
    fontSize: '16px',
    '::placeholder': 
      color: '#aab7c4'
    
  ,
  invalid: 
    color: '#fa755a',
    iconColor: '#fa755a'
  
;

// Create an instance of the card Element.
var card1 = elements1.create('card', style: style);
var card2 = elements2.create('card', style: style);
</script>

<script>
// Add an instance of the card Element into the `card-element` <div>.
card1.mount('#card-element-1');
card2.mount('#card-element-2');

// Handle real-time validation errors from the card Element.
card1.on('change', function(event) 
  var displayError1 = document.getElementById('card-errors-1');
  if (event.error) 
    displayError1.textContent = event.error.message;
   else 
    displayError1.textContent = '';
  
);

card2.on('change', function(event) 
  var displayError2 = document.getElementById('card-errors-2');
  if (event.error) 
    displayError2.textContent = event.error.message;
   else 
    displayError2.textContent = '';
  
);
</script>

<script>
// Handle form submission.
var form1 = document.getElementById('new_order');
form1.addEventListener('submit-1', function(event) 
  event.preventDefault();

  stripe.createToken(card).then(function(result) 
    if (result.error) 
      // Inform the user if there was an error.
      var errorElement1 = document.getElementById('card-errors-1');
      errorElement1.textContent = result.error.message;
     else 
      // Send the token to your server.
      stripeTokenHandler(result.token);
    
  );
);

// Handle form submission.
var form2 = document.getElementById('new_order');
form2.addEventListener('submit-1', function(event) 
  event.preventDefault();

  stripe.createToken(card).then(function(result) 
    if (result.error) 
      // Inform the user if there was an error.
      var errorElement2 = document.getElementById('card-errors-1');
      errorElement2.textContent = result.error.message;
     else 
      // Send the token to your server.
      stripeTokenHandler(result.token);
    
  );
);
</script>

<script>    
// Submit the form with the token ID.
function stripeTokenHandler(token) 
  // Insert the token ID into the form so it gets submitted to the server
  var form1 = document.getElementById('new_order');
  var hiddenInput1 = document.createElement('input');
  hiddenInput1.setAttribute('type', 'hidden');
  hiddenInput1.setAttribute('name', 'stripeToken');
  hiddenInput1.setAttribute('value', token.id);
  form1.appendChild(hiddenInput1);

  // Submit the form
  form1.submit();
;
  
</script>

<script>
// Submit the form with the token ID.
function stripeTokenHandler(token) 
  // Insert the token ID into the form so it gets submitted to the server
  var form2 = document.getElementById('new_order');
  var hiddenInput2 = document.createElement('input');
  hiddenInput2.setAttribute('type', 'hidden');
  hiddenInput2.setAttribute('name', 'stripeToken');
  hiddenInput2.setAttribute('value', token.id);
  form2.appendChild(hiddenInput2);

  // Submit the form
  form2.submit();

;
 
</script>

这是我的 application.js 和表单的 jquery。

$(document).ready(function () 
  $("#groupNumberBooks").on("input", function () 
    var price = 20;
    var numBooks = document.getElementById("groupNumberBooks").value;
    var total = parseFloat(price) * numBooks;

    if (!isNaN(total)) document.getElementById("groupTotal").innerHTML = total;
  );
);

$(document).ready(function() 
  $("#individualNumberBooks").on("input", function () 
    var price = 20;
    var numBooks = document.getElementById("individualNumberBooks").value;
    var total = parseFloat(price) * numBooks;

    if (!isNaN(total)) document.getElementById("individualTotal").innerHTML = total;
  );
);


$(document).ready(function() 
    $("#groupButton").on("click", function () 
    document.getElementById("referBySchool").value = true;
    );
  );


$(document).ready(function () 
  $("#individualButton").on("click", function () 
    document.getElementById("referBySchool").value = false;
  );
);

我所有的 jquery 昨天都在工作,现在,在实现了这个之后,我无法弄清楚为什么它不再工作了。我尝试删除条纹元素,但这也没有将 Jquery 恢复到工作状态......这让我现在真的很困惑!

我可能只是切换回我的主分支并测试它只是为了检查我的理智 XD

【问题讨论】:

【参考方案1】:

将代码包装在 jQuery.ready 回调中并将处理程序直接附加到元素的问题在于,当 Turbolinks 将页面内容替换为 ajax 时,它将无法工作。

相反,您希望创建委托事件处理程序,以便在事件冒泡到 DOM 顶部时捕获事件。

您可以通过将事件处理程序附加到文档本身而不是每个元素并将第二个参数传递给充当过滤器的 jQuery.on 来做到这一点:

$(document).on("input", "#groupNumberBooks", function () 
  let price = 20;
  let total = parseFloat(price) * this.value;
  if (!isNaN(total)) document.getElementById("groupTotal").innerHTML = total;
).on("input", "#individualNumberBooks", function () 
  let price = 20;
  let total = parseFloat(price) * this.value;
  if (!isNaN(total)) document.getElementById("individualTotal").innerHTML = total;
).on("click", "#groupButton", function () 
  document.getElementById("referBySchool").value = true;
).on("click", "#individualButton", function () 
  document.getElementById("referBySchool").value = false;
);

这也利用了这样一个事实,即几乎所有 jQuery 方法都返回它们调用的 jQuery 对象,因此是可链接的。

【讨论】:

以上是关于在我的结帐中实施了 Stripe v3 卡片元素,并且 jquery 停止工作的主要内容,如果未能解决你的问题,请参考以下文章

React-Native,条纹卡元素未显示实时 API 密钥

Paypal 快速结帐支付更多(问题)

如何挂载单个卡片元素 stripe.js?

搜索 PHP 示例新的条带“结帐”集成 stripe-php

如何从 Stripe 结帐表单中删除“在任何地方记住我”选项

React Stripe 结帐多个行项目