【问题标题】:Use Select Element Without Dropdown使用不带下拉菜单的选择元素
【发布时间】:2020-05-21 17:44:17
【问题描述】:

我目前在我的网站上有一个定价页面,它使用 <select><option> html 元素让用户选择定价计划。

这是计划选择下拉菜单的代码:

<select name="plan" class="form-control" id="subscription-plan">
    @foreach ($plans as $key => $plan)
        <option value="{{ $key }}">{{ $plan }}</option>
    @endforeach
</select>

这是表单的样子:

我想添加 2 张包含用户可以选择的计划信息的卡片,并以与下拉菜单相同的方式操作,除非它不是下拉菜单。 id="subscription-plan" 很重要,因为它将用户选择的相应计划发送到 Stripe API,后者根据 Stripe 中设置的金额向用户的信用卡收取费用。有谁知道我如何做到这一点?

我想做这样的事情(但没有下拉样式):

<select name="plan" class="form-control" id="subscription-plan">
                @foreach ($plans as $key => $plan)
                    <option value="{{ $key }}">
                        <div class="card mb-5 mb-lg-0">
                            <div class="card-body">
                                <h5 class="card-title text-muted text-uppercase text-center">Monthly</h5>
                                <h6 class="card-price text-center">$8.44<span class="period">/month</span></h6>
                            </div>
                        </div>
                    </option>
                @endforeach
            </select>

更新: 我试过这个:

@foreach ($plans as $key => $plan)
        <div class="col-6">
            <label>
                <input type="radio" name="plan" value="{{ $key }}" class="card-input-element" id="subscription-plan">

                <div class="panel panel-default card-input">
                    <div class="panel-heading">{{ $plan }}</div>
                    <div class="panel-body">2 Memorials</div>
                </div>
            </label>
        </div>
    @endforeach

此代码有效,并为我提供了具有可选卡的预期效果,但即使用户在选择“年度”计划后提交了他们的信用卡详细信息,Stripe API 现在也只接收“月度”计划。这是因为现在两个输入都有id="subscription-plan"

条带化 JavaScript:

        const stripe = Stripe('{{ env('STRIPE_KEY') }}');
        const elements = stripe.elements();
        const cardElement = elements.create('card');
        cardElement.mount('#card-element');
        const cardHolderName = document.getElementById('card-holder-name');
        const cardButton = document.getElementById('card-button');
        const clientSecret = cardButton.dataset.secret;
        const plan = document.getElementById('subscription-plan').value;

        cardButton.addEventListener('click', async (e) => {
            const { setupIntent, error } = await stripe.handleCardSetup(
                clientSecret, cardElement, {
                    payment_method_data: {
                        billing_details: { name: cardHolderName.value }
                    }
                }
            );
            if (error) {
                // Display "error.message" to the user...
            } else {
                // The card has been verified successfully...
                console.log('handling success', setupIntent.payment_method);

                axios.post('subscribe',{
                    payment_method: setupIntent.payment_method,
                    plan : plan
                }).then((data)=>{
                    location.replace(data.data.success_url)
                });
            }
        });

更新 2: 我已将const plan = document.getElementById('subscription-plan').value; 替换为var plan = document.querySelector('input[name="plan"]:checked').value;。现在,当我尝试提交时,我在控制台中收到Uncaught TypeError: Cannot read property 'value' of null

【问题讨论】:

  • 您是否设置了默认的checked 项目?可能什么都没有设置。还要确保在用户单击单选按钮时更新plan 的值,或者在提交请求之前重新收集它。
  • 是的,我试过了,但还是不行。

标签: javascript html laravel forms stripe-payments


【解决方案1】:

我自己解决了这个问题的 JavaScript 方面。我所做的是将var plan = document.querySelector('input[name="plan"]:checked').value; 更改为var plan;。然后,我补充说: $('input:radio').on('click', function(e) { plan = this.value; });.

现在,表单会根据用户向 Stripe API 选择的选项正确提交正确的计划。在不使用&lt;select&gt;&lt;option&gt; 元素的情况下让这个表单工作对我来说是一项非常困难的任务。这是完成的工作代码:

HTML

<div class="col-6">
        <label>
            <input type="radio" name="plan" value="monthly" class="card-input-element" checked="checked">

            <div class="panel panel-default card-input">
                <div class="panel-heading">Monthly</div>
            </div>
        </label>
    </div>
    <div class="col-6">
        <label>
            <input type="radio" name="plan" value="yearly" class="card-input-element">

            <div class="panel panel-default card-input">
                <div class="panel-heading">Yearly</div>
            </div>
        </label>
    </div>

JavaScript

<script src="{{ asset('js/jquery-3.4.1.min.js') }}"></script>
<script>
    window.addEventListener('load', function() {
        const stripe = Stripe('{{ env('STRIPE_KEY') }}');
        const elements = stripe.elements();
        const cardElement = elements.create('card');
        cardElement.mount('#card-element');
        const cardHolderName = document.getElementById('card-holder-name');
        const cardButton = document.getElementById('card-button');
        const clientSecret = cardButton.dataset.secret;
        var plan;
        $('input:radio').on('click', function(e) {
            plan = this.value;
        });

        cardButton.addEventListener('click', async (e) => {
            const { setupIntent, error } = await stripe.handleCardSetup(
                clientSecret, cardElement, {
                    payment_method_data: {
                        billing_details: { name: cardHolderName.value }
                    }
                }
            );
            if (error) {
                // Display "error.message" to the user...
            } else {
                // The card has been verified successfully...
                console.log('handling success', setupIntent.payment_method);

                axios.post('subscribe',{
                    payment_method: setupIntent.payment_method,
                    plan : plan
                }).then((data)=>{
                    location.replace(data.data.success_url)
                });
            }
        });
    });
</script>

更有经验的程序员可能从一开始就知道如何实现这一点,但我想我们都必须以某种方式学习。谢谢大家的帮助。

【讨论】:

    【解决方案2】:

    您可以简单地将size 属性用于select

    <select name="plan" class="form-control" size=3 id="subscription-plan">
      <option value="1">
        <div class="card mb-5 mb-lg-0">
          <div class="card-body">
            <h5 class="card-title text-muted text-uppercase text-center">Monthly</h5>
            <h6 class="card-price text-center">$8.44<span class="period">/month</span></h6>
          </div>
        </div>
      </option>
    
      <option value="2">
        <div class="card mb-5 mb-lg-0">
          <div class="card-body">
            <h5 class="card-title text-muted text-uppercase text-center">Daily</h5>
            <h6 class="card-price text-center">$0.44<span class="period">/day</span></h6>
          </div>
        </div>
      </option>
      <option value="3">
        <div class="card mb-5 mb-lg-0">
          <div class="card-body">
            <h5 class="card-title text-muted text-uppercase text-center">Yearly</h5>
            <h6 class="card-price text-center">$80.44<span class="period">/year</span></h6>
          </div>
        </div>
      </option>
    </select>

    【讨论】:

      【解决方案3】:

      这应该可以通过迭代创建卡片的计划而不使用 select 来实现。您可以使用onclick 处理程序来解决卡片选择问题,或者将卡片视为单选按钮,就像您在此处看到的那样:https://codepen.io/stefanzweifel/pen/RNvGwz

      然后,您将使用单选值,而不是使用选择值。

      【讨论】:

      • 这段代码解决了我的问题的设计方面。谢谢你,我的朋友。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多