Card Payment with Vue.js Tokenize Fail

Wondering if you have a card payment with vue.js 3 example, or shed any light on the following issue?

I am trying to make a card payment page with vue.js 3. I can’t find any vue.js example, therefore, just tried following the instructions from https://developer.squareup.com/docs/web-payments/take-card-payment.

The card initialized and container rendered successfully, however, card.tokenize() does not work.

Here is the page:


<template>
    <div class="page-checkout">
        <div>
            <form id="payment-form" v-on:submit.prevent="submitOrderForm">
            <div id="card-container"></div>
            <button type="submit" class="button is-info is-fullwidth">Pay with Card</button>
            </form>
        </div>
    </div>
</template>

<script>
export default {
    name: "CheckoutTest",
    data() {
        return {
            card: null,
            errors: []
        }
    },
    mounted() {
        this.initializeCard()
    },
    methods: {
        async initializeCard() {
            const app_id = "replace with sandbox_application_id"
            const location_id = "replace with sandbox_location_id"
            const payments = Square.payments(app_id, location_id)
            await payments.card()
                .then((card) => {
                    card.attach("#card-container")
                    this.card = card
                })
        },
        async submitOrderForm() {
                const tokenResult = await this.card.tokenize()
                console.log(tokenResult.token)
        }
    }
}
</script>

The public index.html page added following script line:

Chrome Console Error Message:
Uncaught (in promise) TokenizationError: Tokenization has failed
An unknown error has occurred
at Qr (square.js:1)
at square.js:1
at Generator.next ()
at ul (square.js:1)
at a (square.js:1)
at square.js:1
at G ((index):909)
at new b ((index):913)
at square.js:1
at Proxy.tokenize (square.js:1)
at Proxy.submitOrderForm (CheckoutTest.vue?a871:37)
at eval (CheckoutTest.vue?a871:4)
at eval (runtime-dom.esm-bundler.js?2725:1450)
at callWithErrorHandling (runtime-core.esm-bundler.js?d2dd:6701)
at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?d2dd:6710)
at HTMLFormElement.invoker (runtime-dom.esm-bundler.js?2725:350)

I figured it out and would like to share my solution here. Welcome any comments or suggestions or better solutions.

The original issue was that the card is a listener, which can not be stored as a data element. I solved it by adding the card to button listener without storing it as a data element. For the sake of simplicity, I stripped out unrelated coding like error handling, etc.

<template>
    <div class="page-makepayment">
        <form id="payment-form">
            <div id="card-container"></div>
            <button type="button" ref="card_button">
                Make Payment
            </button>
        </form>
        <div id="payment-status-container"></div>
    </div>
</template>

<script>

export default {
    name: "MakePayment",

    data() {
        return {
            // card: null,   originally wanted to hold a listener which was the issue
            errors: []
        }
    },
    mounted() {
        this.initializeCard()
    },
    methods: {
        async initializeCard() {
            const square_appid = 'replace with square app id'
            const square_locid = 'replace with square location id'
            const payments = window.Square.payments(square_appid, square_locid)
            let card = await payments.card()        // this card is a listener which cannot be stored as a data element
            await card.attach("#card-container")

            var self = this
            this.$refs.card_button.addEventListener("click", async function (event) {
                const tokenResult = await card.tokenize()
                self.make_payment(tokenResult)
            })
        },

        async make_payment(tokenResult) {
            if ((tokenResult.status == "OK") && (tokenResult.token.length)) {

                // code to process payment with tokenResult.token
            }                
        }
    }
}
</script>

:wave: Glad you were able to figure out the issue and thank you for sharing with the community? :slightly_smiling_face: