What is the process of incorporating externally managed components in Vue.js?

After exploring various libraries that integrate an external library and their DOM elements with Vue.js, I noticed that most of them only add child elements to the Vue-managed DOM node.

To simplify the use of the new Stripe V3 API, I developed Vue-Stripe-Elements. However, I faced challenges when trying to mount Stripe elements to the Vue component.

The typical approach would involve using a `.vue` component like this:

<template>
</template>

<script>
export default {
  // could also be `mounted()`
  beforeMount () {
    const el = Stripe.elements.create('card')
    el.mount(this.$el)
  }
}
</script>

However, it appears that Stripe doesn't just add children to the mounted element, but transcludes or replaces the DOM node altogether. Additionally, Stripe does not support any `VNode`s.

To address this issue, my current solution involves creating a real DOM node and appending it as a child:

<template>
</template>

<script>
export default {
  mounted () {
    const dom_node = document.createElement('div')
    const el = Stripe.elements.create('card')
    el.mount(dom_node)
    this.$el.appendChild(el)
  }
}
</script>

This workaround functions as intended, but it feels like I am working against Vue.js and may inadvertently create unexpected side effects. Could there be a more optimal way to handle this?

Is there a preferred method recommended by Vue.js for addressing this issue?

Any insights on this matter would be greatly appreciated. Thank you!

Answer №1

Using Stripe Elements with Vuejs 2

Utilize refs in Vuejs to access DOM elements.

HTML

<div ref="cardElement"></div>

JS

mounted() {
    const stripe = Stripe('pk');
    const elements = stripe.elements();
    const card = elements.create('card');
    card.mount(this.$refs.cardElement);
}

Answer №2

I encountered the same issue, and while the mounting method is correct to add, I faced an error in larger applications when calling a specific Vue.js component. "Please ensure that the element you are trying to use is still mounted."

Here is the HTML snippet:

<div style="min-height:100px;">
                                            <div class="group">
                                                <h4><span class="label label-default"> Enter Card Details</span> </h4>
                                                <label class="cardlabel">
                                                    <span>Card number</span>
                                                    <div id="card-number-element" class="field"></div>
                                                    <span class="brand"><i class="pf pf-credit-card" id="brand-icon"></i></span>
                                                </label>
                                                <label class="cardlabel">
                                                    <span>Expiry date</span>
                                                    <div id="card-expiry-element" class="field"></div>
                                                </label>
                                                <label class="cardlabel">
                                                    <span>CVC</span>
                                                    <div id="card-cvc-element" class="field"></div>
                                                </label>
                                            </div>
                                        </div>

Vue.js

    (function () {

        let stripe = Stripe('keyhere');
        elements = stripe.elements(),
        cardNumberElementStripe = undefined;
        cardExpiryElementStripe = undefined;
        cardCvcElementStripe = undefined;
        var style = {
            base: {
                iconColor: '#666EE8',
                color: '#31325F',
                lineHeight: '40px',
                fontWeight: 300,
                fontFamily: 'Helvetica Neue',
                fontSize: '15px',

                '::placeholder': {
                    color: '#CFD7E0',
                },
            },
        };
            var purchase= new Vue({
                el: '#purchase',
                mounted() {

                    cardNumberElementStripe = elements.create('cardNumber', {
                        style: style
                    });

                    cardExpiryElementStripe = elements.create('cardExpiry', {
                        style: style
                    });
                    cardCvcElementStripe = elements.create('cardCvc', {
                        style: style
                    });
                    cardNumberElementStripe.mount('#card-number-element');
                    cardExpiryElementStripe.mount('#card-expiry-element');
                    cardCvcElementStripe.mount('#card-cvc-element');

                    cardNumberElementStripe.on('change', function (event) {
                        // Switch brand logo
                        if (event.brand) {
                            if (event.error) { setBrandIcon("unknown"); } else { setBrandIcon(event.brand); }
                        }

                        //setOutcome(event);
                    });
                    function setBrandIcon(brand) {
                        var brandIconElement = document.getElementById('brand-icon');
                        var pfClass = 'pf-credit-card';
                        if (brand in cardBrandToPfClass) {
                            pfClass = cardBrandToPfClass[brand];
                        }
                        for (var i = brandIconElement.classList.length - 1; i >= 0; i--) {
                            brandIconElement.classList.remove(brandIconElement.classList[i]);
                        }
                        brandIconElement.classList.add('pf');
                        brandIconElement.classList.add(pfClass);
                    }
                    var cardBrandToPfClass = {
                        'visa': 'pf-visa',
                        'mastercard': 'pf-mastercard',
                        'amex': 'pf-american-express',
                        'discover': 'pf-discover',
                        'diners': 'pf-diners',
                        'jcb': 'pf-jcb',
                        'unknown': 'pf-credit-card',
                    }



                },
            created() {
      //on the buttn click u are calling this using v-on:click.prevent="payment" 

  payment: function (e) {


                    stripe.createToken(cardNumberElementStripe).then(function (result) {
                        debugger;
                      if (result.token) {
                            cardId = result.token.id;
                           // $("#paymentform").get(0).submit();
                            } else if (result.error) {
                            errorElement.textContent = result.error.message;

                            return;
                        }
                    });
                }        
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Store the user's link for future reference and quickly navigate to the TransferPage in 3 seconds. Then, return

After a user clicks on any button, they will be redirected to the Transfer Page for 3 seconds. Then, they will automatically return to the link they originally clicked on. Schematic: HTML: Vue: ...

The instance is referencing "underscore" during render, but it is not defined as a property or method

I have experience as a skilled react developer, but I've taken over a vue.js project from another developer and managed it for quite some time. Regrettably, I haven't put in the effort to learn vue properly. When using lodash, I encountered an u ...

Implementing IBAN as the default option in Stripe's PaymentElement

The functionality of the react-stripe-js library's IbanElement includes various options such as supportedCountries and placeholderCountry: <IbanElement ... options={{ supportedCountries: ["SEPA"], placeholderCountry: "DE& ...

Is there a way to ensure the content of two divs remains aligned despite changing data within them?

Currently, I have two separate Divs - one displaying temperature data and the other showing humidity levels. <div class="weatherwrap"> <div class="tempwrap" title="Current Temperature"> ...

Retrieve the data stored in an array of objects

code props.thumbnails.forEach(value=>{ console.log(value.photo.thumbnail_url); }) error TypeError: Cannot read property 'thumbnail_url' of undefined Trying to loop through props.thumbnails array and access the thumbnail_url pro ...

Error encountered in Pokemon API: Trying to access property '0' of undefined

My current challenge involves accessing the abilities of my Pokemon, but I keep encountering a recurring error. In my project development using React hooks, I fetched data from the Pokemon API and stored it in setWildPokemon. Utilizing wildPokemon.name suc ...

Guide on retrieving JSON information within an array utilizing a loop function

Hey everyone, I'm facing an issue and I could really use some help. I'm new to working with ajax processing and I'm stuck on a problem. I have successfully retrieved ajax data and now I need to store it in an array. My goal is to populate a ...

What is the best way to incorporate additional data into a TypeScript object that is structured as JSON?

I'm exploring ways to add more elements to an object, but I'm uncertain about the process. My attempts to push data into the object have been unsuccessful. people = [{ name: 'robert', year: 1993 }]; //I aim to achieve this peopl ...

PHP: Extracting the selected value from a dropdown menu and incorporating it into an HTML link

Initially, I created a dropdown list Yet, there is uncertainty surrounding how to incorporate the selected choice (variable) into the input of the HTML <p style="text-align:center"> COVID-19 Checker</p> <br> <label for ...

Attempting to sort through an array by leveraging VueJS and displaying solely the outcomes

Within a JSON file, I have an array of cars containing information such as model, year, brand, image, and description. When the page is loaded, this array populates using a v-for directive. Now, I'm exploring ways to enable users to filter these cars ...

How to adjust the "skipNatural" boolean in AngularJS Smart-Table without altering the smart-table.js script

Looking to customize the "skipNatural" boolean in the smart-table.js file, but concerned about it being overwritten when using Bower for updates. The current setting in the Smart-Table file is as follows: ng.module('smart-table') .constant(&ap ...

What's the best way to adjust the width of the <Input> component in Reactstrap?

How can I adjust the width of an input element in Reactstrap to be smaller? I've attempted to set the bsSize to small without success <InputGroup> <Input type="text" name="searchTxt" value={props.searchText ...

Stable header that jumps to the top when scrolled

I have implemented the JavaScript code below to set the header to a fixed position when it reaches the top of the page so that it remains visible while the user scrolls. Everything appears to be functional, but the header movement is abrupt and not smooth. ...

In a jQuery application, the action of adding text from an input field to a div is triggered by clicking a

It's possible this is a duplicate question, but none of the answers I found solved my issue. I'm attempting to create a jQuery script where text entered into a text box is appended to a div when a button is clicked. This is part of a game I' ...

Exploring the world of form interactions in Angular: A guide to creating dynamic element communication

I have created a form using Angular, and I want to display a specific value in my input field when an element is selected from the dropdown. Additionally, since the values in the dropdown are fetched from a server, I want to show a corresponding label for ...

Use the Vue `this.$router.push` method inside a setTimeout function

I have a landing page '/' that users will see first when they visit our website. I want to display a loading wheel for 5 seconds before automatically redirecting them to the login page '/login'. My Landing.vue page in Vue and Bulma.io ...

Issues with React useState persisting new values between useEffect intervalsHere is a rephrased

I am attempting to store jokes and log a new value every time the interval runs (triggered by a get call) after 5 seconds. However, for some reason, the value is not rendering anything after each interval. I'm not certain if the jokes are actually bei ...

What is the best method for integrating Vuepress into a Nuxt project?

I'm currently working on integrating Vuepress into my Nuxt app. I followed the steps of adding Vuepress using yarn add vuepress@next -D and setting up a docs folder with a readme.md file inside. The issue: The project is only displaying the sidebar a ...

Having trouble with sending a list of items from a VueJS form

I have a VueJS application that calls a patch method to update a user's profile. For example, I am attempting to update the field cities. I created a serializer and views.py using Postman during development. I used Postman to call the patch method fo ...

Securing special characters in cshtml

I am working on a razor view which includes a hidden field called Model.Token. The Token contains special characters that are then appended to a link in the href attribute. <a href='http://<a href="/cdn-cgi/l/email-protection" class="__cf_email ...