Step-by-step guide to generating a Paypal Button using Vue 3 script setup

After going through the PayPal Developer Docs, I'm still struggling to understand how to integrate the PayPal Button into Vue.js. The code examples provided are unclear, and I can't determine if it's related to Vue 2, Vue 3, or even Angular.

1: Firstly, import the script in the parent blade:

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

2: Should I use the button within a script tag of the component?

paypal.Buttons.driver("vue", window.Vue);

3: This part is where I'm getting lost - do I need to include this in app.js?

@ng.core.Component({
  selector: 'my-app',
  template:
    <div id="app">
        <paypal-buttons [props]="{
            createOrder: createOrder,
            onApprove: onApprove
        }"></paypal-buttons>
    </div>
  ,
})
class AppComponent {
    createOrder(data, actions) {
      return actions.order.create({
          purchase_units: [{
              amount: {
                  value: '0.01'
              }
          }]
      });
    }
    onApprove(data, actions) {
      return actions.order.capture();
    }
}
@ng.core.NgModule({
    imports: [
        ng.platformBrowser.BrowserModule,
        paypal.Buttons.driver('angular2', ng.core)
    ],
    declarations: [
        AppComponent
    ],
    bootstrap: [
        AppComponent
    ]
})
class AppModule {}
ng.platformBrowserDynamic
    .platformBrowserDynamic()
    .bootstrapModule(AppModule);

Could it be that this is actually Angular code rather than Vue code?

4: And should I place this in the Vue component?

<div id="container">
  <app></app>
</div>
<script>
  const PayPalButton = paypal.Buttons.driver("vue", window.Vue);

  Vue.component("app", {
    // Style prop for PayPal button must be passed as `style-object` or `styleObject` to avoid conflicts.
    template: `
      <paypal-buttons :on-approve="onApprove" :create-order="createOrder" :on-shipping-change="onShippingChange" :on-error="onError" :style-object="style" />
    `,
    components: {
      "paypal-buttons": PayPalButton,
    },

    computed: {
      createOrder: function () {
        return (data, actions) => {
          return actions.order.create({
            purchase_units: [
              {
                amount: {
                  value: "10",
                },
              },
            ],
          });
        }
      },
      onApprove: function () {
        return (data, actions) => {
          return actions.order.capture();
        }
      },
      onShippingChange: function () {
        return (data, actions) => {
          if (data.shipping_address.country_code !== 'US') {
            return actions.reject();
          }
          return actions.resolve();
        }
      },
      onError: function () {
        return (err) => {
          console.error(err);
          window.location.href = "/your-error-page-here";
        }
      },
      style: function () {
        return {
          shape: 'pill',
          color: 'gold',
          layout: 'horizontal',
          label: 'paypal',
          tagline: false
        }
      },
    },
  });

  const vm = new Vue({
    el: "#container",
  });
</script>

I'm now wondering how I can create a simple PayPal button with Vue 3's script setup. The PayPal CDN has been imported in the parent blade file.

Is there a way to achieve something like this:

<script setup>
import {onMounted} from "vue";

onMounted(() => {
    // Create component using -> paypal.Buttons.driver("vue", window.Vue);
})
</script>


<template>
  <div id="checkout" class="checkout">
    <paypal-buttons></paypal-buttons>
  </div>
</template>

Answer №1

Here's a suggestion for how you can implement this:

  • Start by installing the official paypal-js npm package: npm install @paypal/paypal-js

Next, create your PaypalButtons Component like this:

<script setup>
import {Inertia} from '@inertiajs/inertia';
import {loadScript} from '@paypal/paypal-js';
import {onMounted} from 'vue';

const props = defineProps({
    // You can include a reference here if needed
    reference: Object
});

onMounted(async() => {
    try {
        const paypal = await loadScript({
            'client-id': <your-paypal-client-id>
        });

        await paypal.Buttons({
            createOrder: function(data, actions) {
                return actions.order.create({
                    purchase_units: [{
                        amount: {
                            value: '<your-price>',  // For example: reference.price
                        },
                    }],
                });
            },
            onApprove: function(data, actions) {
                return actions.order.capture().then(function(orderData) {
                    // Order successfully captured!
                    // e.g. Inertia.post(route('order.update', reference.orderId)
                });
            },
            style: {
                layout: 'vertical',
                color: 'gold',
                shape: 'rect',
                label: 'paypal',
            },
            fundingSource: paypal.FUNDING.PAYPAL,  // Optional - customize button options
        }).render('#paypal-button-container');
    } catch (error) {
        console.error(error);  // Add proper error handling
    }
});
</script>

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

Now you can use it like this:

<PaypalButtons :reference="reference" />

Answer №2

The documentation provided by Paypal can be a bit confusing. When integrating with the server, it seems to follow these steps:

If you are using laravel as your backend, include this in your app.blade.php/welcome.blade.php file:

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

Then, your vue component should look something like this:

<script setup>
import {onMounted} from "vue";

onMounted(() => {
    paypal.Buttons({
        // Implement functions here
    }).render('#paypal-button-container');
})

</script>

<template>
  <div id="checkout" class="checkout">
    <div id="paypal-button-container"></div>
  </div>
</template>

The displayed payment methods are automatically determined based on your IP address. You can hide certain payment methods by adjusting the script import like this:

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&disable-funding=card,giropay,sepa,sofort"></script>

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

Using Traefik for HTTPS redirection with Docker Compose, the Vue+Nginx application is encountering a 404

Hello everyone, I am a newbie developer and excited to share that I am deploying my first full stack project. I'm currently working on running a vuejs+nginx client app in a docker-compose setup which includes mysql, a nodejs backend, and traefik for ...

What are the potential causes of an asynchronous error in a WebGLRenderingContext?

While running an animation loop, I encountered a peculiar error message that reads... GL ERROR :GL_INVALID_OPERATION : glDrawElements: Source and destination textures of the draw are the same. This error seems to occur randomly after 2 or 3 animation fr ...

Include dropdown lists for selecting the year, month, and day on a web page

Is there a way to implement a dropdown style date selector that dynamically updates the number of days based on the selected year and month using JavaScript? For example, February 2008 has 29 days, April has 30 days, and June has 31 days. Any suggestions ...

Tips for creating multiple files using nodejs and express

I am currently working on developing a personalized code editor that consists of 3 textareas: html, css, and javascript. The objective is to save the data from each textarea into individual files. With the help of express and nodejs, I have successfully m ...

The method by which AngularJS identifies the appropriate property within a return value

In Angular, watchers are utilized to identify property changes and trigger a listener function. An example of a watcher declaration is shown below: $scope.food = "chicken"; scope.$watch( function() { return food; }, function(newValue, oldValue) { ...

Eliminate error class in jQuery Validate once validation is successful

I'm having an issue with the jQuery Validate plugin. Even after a field is successfully validated, the "error-message box" continues to be displayed. How can I remove this box? Here's my code: CSS: .register-box .field .has-error{ border ...

Gain entry to Zurb Foundation for Apps modules within your AngularJS application

Currently, I am developing an AngularJS application utilizing Foundation for Apps. One key element in my layout is a Foundation Apps panel that serves as the top menu. <div zf-panel="" id="topMenu" position="top" class="panel-fixed">...</div> ...

How can I retrieve a variable in a JavaScript AJAX POST request?

Similar Question: How to retrieve a variable set during an Ajax request I am facing a challenge, as I am making an ajax call and receiving a number as the response. My query is, how can I assign this returned number to a variable that is accessible ou ...

JavaScript - Retrieve events from an element and assign them to a keyboard button

I am currently curious about the following scenario: Suppose I have an element with a particular event. For example, when this element is clicked, it triggers alert('clicked); Now, my question is: Is there a way to capture the events of this element ...

What is the best way to generate a new Object using an Object that contains Arrays?

I currently have a global array saved with a catalog and a list of items that the user has saved. My task is to generate a new array of Objects (with arrays) containing only the items saved by the user. I am working with javascript in react-native, and I ...

CSS Class Returns to Inactive State

One of my tasks involves adding a new class to an image. .bbbLink img { outline: 1px solid #ddd; border-top: 1px solid #fff; padding: 10px; background: #f0f0f0; } When hovering over the image, I apply the following styles, .bbbLink img ...

Implementing Jet Application Mark in Laravel version 8.x

As I was browsing through Laravel 8.x, I stumbled upon jet-application-mark which does not have an ending tag as expected for a Vue component... <div class="flex-shrink-0 flex items-center"> <a href="/dashboard"> ...

Trouble is arising in rendering events with years before 100 (specifically years 0000 - 0099) when using the ISO8601 format in fullCalendar

I've created a Calendar that showcases various events using fullcalendar. The events span from the years 0001 to 6000. Fullcalendar requires dates in ISO8601 format, and I am providing them as such. Events from the years 0100-6000 render perfectly w ...

Tips for maintaining the state of a page submitted via Turbolinks using Rails 5 and jQuery

My current challenge involves toggling the visibility of a section when a specific element is clicked. Initially, I was able to achieve this functionality successfully. However, complications arose as my application revolves around a todo list where tasks ...

Utilizing Browserify routes and configuring Webstorm

When building my project using gulp and browserify, I made use of path resolution for easier navigation. By following this guide, I configured browserify as shown below: var b = browserify('./app', {paths: ['./node_modules','./src ...

Filling in a text field with the text content (rather than the value) from a dropdown menu

Presently, I have the select box with the id "title" populating a text field with the id "costcenter". The current code works perfectly fine when using the VALUE of the select box to trigger the population of the cost center field. However, my requirement ...

Duplicate a form based on the selected option

My goal is to duplicate a form based on the numerical value selected from the drop-down menu. You can find the corresponding code in this JSFiddle. Here is the HTML code: <div class="travel_tour-info"> <h3>How many people are you booking for? ...

Obtain details regarding a worker's collision

This code snippet is being used to manage cluster crashes within a node application cluster.on('exit', function (worker, code, signal) { console.log("error in cluster",worker); console.log("cluster code",code); console.l ...

Deleting outdated files in a temporary uploads directory - NodeJS best practices

My process for removing old files from a tmp upload directory involves the code below: fs.readdir( dirPath, function( err, files ) { if ( err ) return console.log( err ); if (files.length > 0) { files.forEach(function( file ) { ...

Unable to locate the specified script using node.js

Recently, I've started working with Javascript and Node.js. My current project is utilizing OpenMCT (https://github.com/nasa/openmct) and I'm facing an issue when trying to integrate a script as a plugin in an index.html file. Upon starting the N ...