Attempting to integrate Stripe Elements into a Vue SPA single file component has presented me with a challenge in the form of this error:
IntegrationError: Missing argument. Make sure to call mount() with a valid DOM element or selector.
at new t (https://js.stripe.com/v3/:1:10765)
at t.<anonymous> (https://js.stripe.com/v3/:1:97008)
at t.<anonymous> (https://js.stripe.com/v3/:1:26038)
at VueComponent.createCardElement (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/stripe/card-modal.vue?vue&type=script&lang=js&:143:17)
at VueComponent.stripePubKey (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/stripe/card-modal.vue?vue&type=script&lang=js&:177:14)
at Watcher.run (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:4562:19)
at flushSchedulerQueue (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:4304:13)
at Array.eval (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:1979:12)
at flushCallbacks (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:1905:14)
The issue arises during the execution, specifically failing at the .mount() function due to an absence of a valid DOM element/selector.
Here is the summary of methods I have experimented with:
- The code executes after the component's lifecycle (My component is structured as a Buefy modal, triggering the stripe element mount logic when the modal becomes visible).
- The code runs immediately following Stripe's official Vue example.
- The code executes right after the 'stripePubKey' property ceases to be null (Noting that the 'stripePubKey' is updated within the mounted segment of the Vue lifecycle).
Below is the snippet for the component once scenario 3 unfolds:
<template>
<div>
<b-button class="button is-info is-rounded"
size="is-medium"
icon-left="credit-card"
:loading="isLoading"
@click="isModalActive = true" v-if="!cardId">
Add a card
</b-button>
<button class="button is-warning"
:loading="isLoading"
@click="isModalActive = true" v-else>
Edit
</button>
<b-modal has-modal-card trap-focus :active.sync="isModalActive">
<b-loading :active.sync="isModalLoading" :can-cancel="false" />
<form v-on:submit.prevent="create()" class="has-text-justified">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title" v-if="!cardId">Add a card</p>
<p class="modal-card-title" v-else>Edit a card</p>
</header>
<section class="modal-card-body">
<div ref="cardo"></div>
<p v-show="elementsError" id="card-errors" v-text="elementsError" />
</section>
<footer class="modal-card-foot">
<button class="button" type="button" @click="isModalActive = false">Close</button>
<button class="button is-primary" type="submit" :disabled="!complete">Add</button>
</footer>
</div>
</form>
</b-modal>
</div>
</template>
... <!-- Skipping the script section for brevity -->
In addition, the aforementioned component attempts to mount the card element using $refs, even though the official Stripe VueJS sample uses '#card-element' for the same purpose. Both methods were tested without success!
For reference, here is my index.html for the SPA which includes the Stripe script placement:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Roboto:100:300,400,500,700,900|Material+Icons" rel="stylesheet">
<title>Nozomi</title>
</head>
<body>
<noscript>
<strong>We're sorry but Nozomi doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
<script src="https://js.stripe.com/v3/"></script>
</html>