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:
<!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?
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.
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).
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”.
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({ ...