Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Gabotronix's avatar

Stripe: multiple elements payment forms possible?

Hi everybody, I'm trying to have two payment forms in a single component, problem is I'm getting the following error:

Can only create one Element of type cardNumber

At first one of the forms will be hidden but the user can choose to make the other appear clicking a button to add a new source.

Is it possible to have more than one payment form in the same page?

This is my full component:

<template>
<div class="STRIPEform21_maincontainer">
    <layout-title-4 :number="2" :text="'Elije tu forma de pago.'"></layout-title-4>
    <form v-show="!showPaymentForm" id="payment-form" method="POST" class="STRIPEform21_form_maincontainer">
            <div class="STRIPEform21_form_row_container">
                <span class="STRIPEform21_form_row_label">Nombre del titular</span>
                <input class="STRIPEform21_form_row_input" type="text">
            </div>
            <div class="STRIPEform21_form_row_container">
                <span class="STRIPEform21_form_row_label">Número de tarjeta</span>
                <div id="card-number-element" class="STRIPEform21_form_row_input"></div>
            </div>
            <div class="STRIPEform21_form_row_container">
                <span class="STRIPEform21_form_row_label">Fecha de caducidad</span>
                <div id="card-expiry-element" class="STRIPEform21_form_row_input"></div>
            </div>
            <div class="STRIPEform21_form_row_container">
                <span class="STRIPEform21_form_row_label">CVC</span>
                <div id="card-cvc-element" class="STRIPEform21_form_row_input"></div>
            </div>
            <button class="STRIPEform21_form_button_container" type="submit" @click="addSource();">
                <span class="STRIPEform21_form_button_text">Añadir</span>
            </button>
        </form>
    <div class="STRIPEform21_column_container">
        <div class="STRIPEform21_select_row_container">
            <span class="STRIPEform21_select_row_label">Elije tu forma de pago:</span>
            <select class="STRIPEform21_select_row_input">
                <option class="STRIPEform21_select_row_option" >✱✱✱✱ ✱✱✱✱ ✱✱✱✱ 4242 - 05/22</option>
            </select>
        </div>
        <div class="STRIPEform21_column_center_container">
            <span class="STRIPEform21_column_text">O elije otra opción:</span>
            <button class="STRIPEform21_column_button_container" @click="showPaymentForm = true">
                <i class="STRIPEform21_column_button_icon fa fa-plus"></i>
                <img class="STRIPEform21_column_button_image" src="/img/misc/credit-cards/rectangle-generic.svg">
                <span class="STRIPEform21_column_button_text">Añadir otra tarjeta de credito</span>
            </button>
        </div>
    </div>
    <div v-show="showPaymentForm" class="STRIPEform21_tab_container">
        <i class="STRIPEform21_close fa fa-times" @click="showPaymentForm = false;"></i>
        <form id="payment-form" method="POST" class="STRIPEform21_form_maincontainer">
            <div class="STRIPEform21_form_row_container">
                <span class="STRIPEform21_form_row_label">Nombre del titular</span>
                <input class="STRIPEform21_form_row_input" type="text">
            </div>
            <div class="STRIPEform21_form_row_container">
                <span class="STRIPEform21_form_row_label">Número de tarjeta</span>
                <div id="card-number-element-2" class="STRIPEform21_form_row_input"></div>
            </div>
            <div class="STRIPEform21_form_row_container">
                <span class="STRIPEform21_form_row_label">Fecha de caducidad</span>
                <div id="card-expiry-element-2" class="STRIPEform21_form_row_input"></div>
            </div>
            <div class="STRIPEform21_form_row_container">
                <span class="STRIPEform21_form_row_label">CVC</span>
                <div id="card-cvc-element-2" class="STRIPEform21_form_row_input"></div>
            </div>
            <button class="STRIPEform21_form_button_container" type="submit" @click="addSource();">
                <span class="STRIPEform21_form_button_text">Añadir</span>
            </button>
        </form>
    </div>
</div>
</template>
<!--SCRIPTS-->
<script>
import { stripePK } from '../../config/stripe.js';
import { mapState, mapActions } from 'vuex';
export default {
name: 'STRIPEform31',


computed:{
    ...mapState('Stripe', ['customer', 'customerSources', 'loadingStatus', 'errors']),
},


data: function () {
    return {
       showPaymentForm: false, 
       stripePK: stripePK,
    }
},


props: {
    globals: {required:true}
},


mounted() {
    console.log(this.$options.name + ' component succesfully mounted');
    this.getCustomerSources();

    let stripe = Stripe(this.stripePK);
    let elements = stripe.elements();

    // Custom styling can be passed to options when creating an Element.
    let style = {
        base: {
            color: 'rgba(0,0,0,0.7)',
            fontSmoothing: 'antialiased',
            fontSize: '16px',

            '::placeholder': {
                color: 'rgba(0,0,0,0.7)'
            }
        },
        
        invalid: {
            color: '#fa755a',
            iconColor: '#fa755a'
        }
    };

    // Create an instance of the card Element.
    //let card = elements.create('card', {style: style});
    //card.mount('#card-element');

    let cardNumberElement = elements.create('cardNumber', {style: style});
    cardNumberElement.mount('#card-number-element');

    let cardExpiryElement = elements.create('cardExpiry', {style: style});
    cardExpiryElement.mount('#card-expiry-element');

    let cardCvcElement = elements.create('cardCvc', {style: style});
    cardCvcElement.mount('#card-cvc-element');

    let cardNumberElement2 = elements.create('cardNumber', {style: style});
    cardNumberElement2.mount('#card-number-element2');

    let cardExpiryElement2 = elements.create('cardExpiry', {style: style});
    cardExpiryElement2.mount('#card-expiry-element-2');

    let cardCvcElement2 = elements.create('cardCvc', {style: style});
    cardCvcElement2.mount('#card-cvc-element-2');

    // Handle real-time validation errors from the card Element.
    cardNumberElement.addEventListener('change', function(event) {
        if (event.error) {
            $('#card-errors').text(event.error.message);
        } 
        else {
            $('#card-errors').text('');
        }
    });

    // Handle form submission.
    $('#stripe_form').submit(function(e) {
        e.preventDefault();

        stripe.createSource(cardNumberElement).then(function(result) {//or card
            if (result.error) {
                // Inform the user if there was an error.
                $('.card-errors').text(result.error.message);
            } 
            else {
                // Send the source to your server.
                stripeSourceHandler(result.source);
            }
        });
    });

    // Submit the form with the source ID.
    function stripeSourceHandler(source) {
        // Insert the source ID into the form so it gets submitted to the server
        let form = $('#stripe_form');

        $('<input>').attr({
            type: 'hidden',
            name: 'stripeSource',
            value: source.id,
        }).appendTo('form');

        // Submit the form
        form.submit();
    }
},


methods: {
    ...mapActions('Stripe', ['addSource', 'getCustomerSources']),

    openPaymentTab: function(){
        this.paymentTab = true;
    },

    closePaymentTab: function(){
        this.paymentTab = true;
    }
}


};
</script>
<!--STYLES-->
<style scoped>
</style>
0 likes
0 replies

Please or to participate in this conversation.