Embedding PayPal buttons within a Vue.js component

I am in the process of integrating PayPal order buttons into my Vue.js component.

I have been referencing the official documentation which outlines three key steps:

  1. Import the PayPal SDK script
  2. Create a <div> element where the buttons will be displayed
  3. Add JavaScript code to configure callbacks and render the buttons using the paypal variable

Below is an example implementation in a basic HTML file:

<!-- 1 -->

<script src="https://www.paypal.com/sdk/js?&client-id=xxx"></script>

<!-- 2 -->

<div id="paypal-button-container"></div>

<!-- 3 -->

<script>
  paypal.Buttons({
    createOrder: function (data, actions) {
      return fetch('http://localhost:8081/api/v1/pay-pal/create-order', {
        method: 'POST'
      }).then(function(res) {
        return res.json();
      }).then(function(data) {
        return data.id;
      });
    },
    onApprove: function (data, actions) {
      return fetch('http://localhost:8081/api/v1/pay-pal/capture-order/' + data.orderID, {
        method: 'POST'
      }).then(function(res) {
        if (!res.ok) {
          alert('Something went wrong');
        }
      });
    }
  }).render('#paypal-button-container');
</script>

The above code functions correctly. However, I am struggling with implementing this within a Vue.js component.

For step 1, I utilized the mounted() lifecycle hook as follows:

mounted() {
    let payPalSdk = document.createElement('script')
    payPalSdk.setAttribute('src', 'https://www.paypal.com/sdk/js?&client-id=xxx')
    document.head.appendChild(payPalSdk)
}

Step 2 was straightforward, by adding the div element to the template.

My challenge lies in deciding where to place the JavaScript code for step 3.

I attempted to include it in an external js file and load it within the mounted() method like so:

mounted() {
    let payPalSdk = document.createElement('script')
    payPalSdk.setAttribute('src', 'https://www.paypal.com/sdk/js?&client-id=xxx')
    document.head.appendChild(payPalSdk)

    let payPalScript = document.createElement('script')
    payPalScript.setAttribute('src', '/js/paypal.js')
    document.head.appendChild(payPalScript)
}

Here is the content of paypal.js:

  paypal.Buttons({
    createOrder: function (data, actions) {
      return fetch('http://localhost:8081/api/v1/pay-pal/create-order', {
        method: 'POST'
      }).then(function(res) {
        return res.json();
      }).then(function(data) {
        return data.id;
      });
    },
    onApprove: function (data, actions) {
      return fetch('http://localhost:8081/api/v1/pay-pal/capture-order/' + data.orderID, {
        method: 'POST'
      }).then(function(res) {
        if (!res.ok) {
          alert('Something went wrong');
        }
      });
    }
  }).render('#paypal-button-container');

While the buttons are rendering, the console presents an error message:

buttons?style.layout…re&commit=true:1182 unhandled_error 
{err: "Error: Invalid json: .↵    at XMLHttpRequest.<anon…rrency=USD&intent=capture&commit=true:1182:22901)", timestamp: "1605367583366", referer: "www.sandbox.paypal.com", sdkCorrelationID: "7d650f42fd450", sessionID: "09b33213cd_mtu6mjy6mja", …}
buttonCorrelationID: "72135879fd67d"
buttonSessionID: "473d7ab57f_mtu6mjy6mja"
env: "sandbox"
...

(Truncated due to character limit)

Additionally, placing the code directly inside the mounted() hook led to issues as the paypal variable was undefined in that context.

Answer №1

Consider implementing this code snippet within the mounted() lifecycle hook to see if incorporating a callback upon PayPal JS loading or utilizing client-side createOrder/onApprove functions yield different results

function loadAsync(url, callback) {
  var s = document.createElement('script');
  s.setAttribute('src', url); s.onload = callback;
  document.head.insertBefore(s, document.head.firstElementChild);
}

loadAsync('https://www.paypal.com/sdk/js?client-id=sb&currency=USD', function() {
  paypal.Buttons({

    // Set up the transaction
    createOrder: function(data, actions) {
        return actions.order.create({
            purchase_units: [{
                amount: {
                    value: '0.01'
                }
            }]
        });
    },

    // Finalize the transaction
    onApprove: function(data, actions) {
        return actions.order.capture().then(function(details) {
            // Display a success message to the buyer
            alert('Transaction completed by ' + details.payer.name.given_name);
        });
    }

  }).render('#paypal-button-container');
});

To seamlessly integrate the client-side approval logic with your server backend, I suggest referencing the error handling approach outlined at https://developer.paypal.com/demo/checkout/#/pattern/server

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

How is it possible for JavaScript functions to be accessed prior to being defined?

Similar Question: Why can I access a function before it's declared in JavaScript? Unexpectedly, the following code results in an error due to the undefined Foo: window.Foo = Foo; This code snippet also triggers the same error: window.Foo = Foo ...

What is the most efficient method for iterating through an array stored in JSON format?

Looking for help with parsing a JSON file that contains a list of departures. I want to loop through each bus line and display them in separate div elements like this: <div class="bus"> <div class="line">departure.line</div> < ...

Exploring HTML tables in JavaScript / jQuery by leveraging the 'headers' attribute

If we consider the table structure below: <table> <thead> <tr> <th id="th_00">&nbsp;</th> <th id="th_01">TH 01</th> <th id="th_02">TH 02</th> <th id="th_03">TH 03< ...

Is there a way to transfer innerHTML to an onClick function in Typescript?

My goal is to pass the content of the Square element as innerHTML to the onClick function. I've attempted passing just i, but it always ends up being 100. Is there a way to only pass i when it matches the value going into the Square, or can the innerH ...

Having trouble loading JSON api data in React?

Recently, I've delved into the world of React and was assigned a task to fetch data from a JSON API and showcase it on the screen. Initially, everything went smoothly while practicing with this URL - https://jsonplaceholder.typicode.com/users. Howeve ...

Tips for displaying javascript code containing variables in the executeScript method

I'm currently working on a selenium script that involves executing JavaScript code using the executeScript method. I've run into an issue when it comes to handling single (') and double quotes (") while passing variables. Not Working: js.e ...

Resolving a Tricky Challenge with jQuery's

I am facing an issue with a function that animates images through crossfading. This function is responsible for rotating banners on a website. By calling the function as animateSlideshow("play"), it starts animating and sets up a timeout. On the other hand ...

Error during Docker build: Files with duplicate paths are not supported

Here is the Dockerfile code that I am using: FROM node:16.10-alpine3.12 as base RUN apk update RUN apk add git WORKDIR /app COPY package.json . FROM base as builder RUN npm i COPY . . RUN npm run build FROM base as prod WORKDIR /exfront COPY --from=build ...

Vue allows you to use regular expressions with arrays

Looking to implement a list filtering system using checkboxes. This is how I am looping through an array from VUEX: <div class="checkbox" v-for="brand in brands" :key="brand.id"> <input name="brands" typ ...

Steps to turn off Google Analytics while working on a local server:

I implement this code for tracking with Google Analytics, <noscript> <iframe src="//www.googletagmanager.com/ns.html?id=GTM-KCQGLT" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> as well as this ...

Unlocking the request object within a GraphQL resolver with Apollo-Server-Express

My express server is standard and I'm using GraphQL with it const server = express(); server.use('/graphql', bodyParser.json(), graphqlExpress({ schema })); I am wondering how to access the request object within a resolver. Specifically, ...

Unable to close Bootstrap sidebar menu on mobile devices

I implemented a sidebar menu for mobile that opens when you click on the hamburger icon, with a dark overlay covering the body. The issue I encountered is that on mobile devices, the visibility of the menu does not change when clicked outside of it. It wor ...

What is the process for retrieving prop details when making a GET API request in VUE 3?

Hey there! I am currently diving into learning VUE 3 with the router but I'm struggling to grasp how to fetch data based on an id. Can anyone help me out? Every time I check my console log, it keeps showing undefined as the result. What am I doing wr ...

The property is returning an empty string, but the function is functioning perfectly

Check out this related Stack Overflow post exports.getAddress = asyncHandler(async (req, res, next) => { var lon = req.query.lon; var lat = req.query.lat; var formattedAddress = ""; var url1 = 'url' request(url1 ...

"Exploring the Possibilities of Dynamic Styling with VueJS

I am facing an issue with a data property called editMode set on a Vueity Card. When I click on a button, the editMode switches to true and an icon appears on the v-img. However, I want to adjust the opacity of the image to 0.3 when editMode is true, witho ...

The click function is a member of an object within an emit event

I stumbled upon the code snippet below, which triggers the notification-alert event and passes an object as a parameter. this.$root.$emit('notification-alert', { text, type: 'warning', click: () = ...

MongoDB: Restrict the number of records returned to an increasing count within a specified range

Currently, I am working on a Node project that uses Mongoose. In my code, I have the following query: var query = Model.aggregate( { $match: { id: id } }, { $sort: { created: -1 } }, { $project: { name: ...

Utilizing JavaScript regex to eliminate multiple backslashes while maintaining the special character

To load JSON data with multiple backslashes before a newline character, we are utilizing JavaScript. An example of this is: { "test": { "title": "line 1\\\\\\\nline2" } } Various RegEx patterns have been ...

Tips for automatically filling in fields when a button is clicked in a React application

I'm attempting to pre-fill the form fields that are duplicated with data from already filled fields. When I click the "Add Fields" button, new fields are replicated, but I want them to be pre-populated with data from existing fields. How can I access ...

Passing an object using Ionic Vue's router-link

Looking to send an object as a prop to another page using a router-link in Ionic-Vue. When clicking on the link I created, it looks like nothing is getting passed through. Here's the link I currently have: <router-link :to="{ name: 'mov ...