How to integrate PayPal checkout button into Aurelia template


#1

So, I’m trying to add support for PayPal into my Aurelia app. I’m attempting to implement what they would call their “Server side express checkout using REST”. My issue is trying to incorporate their “checkout button” into the Aurelia template. The provide an example of how to do this with vanilla java script and html:

https://developer.paypal.com/demo/checkout/#/pattern/server

which looks like this:

<!DOCTYPE html>

<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://www.paypalobjects.com/api/checkout.js"></script>
</head>

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


    <script>
        paypal.Button.render({

            env: 'sandbox', // sandbox | production

            // Show the buyer a 'Pay Now' button in the checkout flow
            commit: true,

            // payment() is called when the button is clicked
            payment: function() {

                // Set up a url on your server to create the payment
                var CREATE_URL = '/demo/checkout/api/paypal/payment/create/';

                // Make a call to your server to set up the payment
                return paypal.request.post(CREATE_URL)
                    .then(function(res) {
                        return res.paymentID;
                    });
            },

            // onAuthorize() is called when the buyer approves the payment
            onAuthorize: function(data, actions) {

                // Set up a url on your server to execute the payment
                var EXECUTE_URL = '/demo/checkout/api/paypal/payment/execute/';

                // Set up the data you need to pass to your server
                var data = {
                    paymentID: data.paymentID,
                    payerID: data.payerID
                };

                // Make a call to your server to execute the payment
                return paypal.request.post(EXECUTE_URL, data)
                    .then(function (res) {
                        window.alert('Payment Complete!');
                    });
            }

        }, '#paypal-button-container');
    </script>
</body>

Evidently, PayPal is implementing something kindof like a template method where it first calls my payment function, then presents it’s user interface to walk the user through authorizing the payment, then calls an OnAuthorized function where I can make another server call to record what’s happened and finalize the interaction.

Has anyone attempted to do this? Or have an advice on how I could proceed with this?

Regards,
Rob


#2

I’ve made some progress on this by doing the following:

            <paypal-button client.bind="client" env.bind="env" commit="true" payment.bind="payment(data, actions)" onAuthorize.bind="OnAuthorize(data, actions)" ref="payPalButton"></paypal-button>

and adding the following in the .ts file:

env = "sandbox";
   client = { sandbox: 'AWi18rxt26-hrueMoPZ0tpGEOJnNT4QkiMQst9pYgaQNAfS1FLFxkxQuiaqRBj1vV5PmgHX_jA_c1ncL' }
   payment(data: any, actions: any)
   {
      return actions.payment.create({
         transactions: [
            {
               amount: { total: "1.00", currency: "USD" }
            }
         ]
      });
   }
   onAuthorize(data: any, actions: any)
   {
      // add call to server here.
   }

When watching under the debugger, the properties are being accessed and the functions are being called, but on the function calls, data and actions are undefined.

Any ideas?

Thanks,
Rob


#3

there is a call binding that you want to use
check out this
http://aurelia.io/docs/binding/basics#function-references


#4

Here is a starting point for you

take a look:


#5

Thank you very much… I’ll report back later today. I really appreciate your time.


#6

This has gotten me a long way, but I have one other issue I’m running into with the code in the Gist. In the attached method, it does this:

 attached(){
    debugger 
      paypal.Button.render({

I’m using TypeScript and get an error about paypal not being defined. Of course, if I change the file to be paypal-button.js, I get an error about “@ is an invalid character, perhaps you need a loader for this filetype” (paraphrased, but complaining about the @inject decorator).

Any thoughts?

Thanks for the help!
Rob


#7

After imports add
Declare var paypal:any


#8

So, I modified paypal-button.ts to the following:

import { autoinject } from 'aurelia-framework';

@autoinject
export class PaypalButton
{
   constructor(element:Element)
   {
      this.element = element;
   }

   attached()
   {
      this.paypal.Button.render({
            env: 'sandbox', // sandbox | production

            // Show the buyer a 'Pay Now' button in the checkout flow
            commit: true,

            // payment() is called when the button is clicked
            payment: function()
            {
               // Set up a url on your server to create the payment
               var CREATE_URL = '/demo/checkout/api/paypal/payment/create/';

               // Make a call to your server to set up the payment
            },

            // onAuthorize() is called when the buyer approves the payment
            onAuthorize: function(data: any, actions:any)
            {
               // Set up a url on your server to execute the payment
               var EXECUTE_URL = '/demo/checkout/api/paypal/payment/execute/';

               // Set up the data you need to pass to your server
               var data1 = {
                  paymentID: data.paymentID,
                  payerID: data.payerID
               };

               // Make a call to your server to execute the payment
            }

         },
         this.element.querySelector('.paypal-button-container'));
   }

   element:Element;
   paypal:any;
}

which results in an error message at run-time of “Cannot read property ‘Button’ of undefined”

if I try adding a ref=“paypal” to

<template>
    <div click.delegate="payMe()" class="paypal-button-container" ref="paypal"> pay pal button</div>
</template>

, that, of course, provides a value, but just moves the error a little further down the call chain, i.e., the error is now “Cannot read property ‘render’ of undefined”.

If I’ve made a mistake and the

Declare var paypal:any

should have gone somewhere else, let me know.

Again, thanks for the help.

Rob


#9

Yeah… other place…
with declare var paypal:any you tell typescript that paypal is a global variable declared somwhere else… and it should not bug you.

so you put it after imports.
and do not use this.paypal…
paypal’s script adds a global variable…
so with declare you tell typescript that it will be available at runtime

import { autoinject } from 'aurelia-framework';

declare var paypal:any

@autoinject
export class PaypalButton
constructor(private element:Element) // private will make element 
//a property on your class.. you can remove declaration @ the end 
{
}
attached()
   {
      paypal.Button.render({ ...

could not find a reference to typescript docs
http://blogs.microsoft.co.il/gilf/2013/07/22/quick-tip-typescript-declare-keyword/


#10

Awesome! Thanks so much for the help. I learned a lot. Wish I could buy you a beverage of your choice!

Regards,
Rob


#11

you could buy beverage for the whole team instead (-:
https://opencollective.com/aurelia