Visa Developer Community

Highlighted
Regular Visitor

Visa checkout integration Angular 6 with type script

i want to integrate visa checkout to my angular 6 application. following is the html file and the type script file basic flow. its not functioning properly with typescript code. 
 
html file
 
<img class="v-button" role="button" tabindex="0" src="https://sandbox.secure.checkout.visa.com/wallet-services-web/xo/button.png" alt="Visa Checkout" />
 
 
 
typescript file
 
declare var V;
 
export class CheckoutComponent implements AfterViewInit {

ngAfterViewInit() {
console.log('ngAfterViewInit: Visa Checkout sdk.js is loaded and button is displayed.');
this.onVisaCheckoutReady();
}

onVisaCheckoutReady() {
V.init( {
apikey: "XXXXXXXXXXXXX",
 
settings: {
},
paymentRequest:{
currencyCode: "USD",
total: "10.00"
}
});
V.on("payment.success", function(payment) {
// document.write(JSON.stringify(payment));
console.log(payment);
$.ajax({
type: 'POST',
url: 'Decrypt.php',
data: {json: JSON.stringify(payment)},
dataType: 'json',
success: function(data){
// var response = JSON.stringify(data);
document.write(data);
alert("Successful callback");
},
error: function() {
console.log('Cannot retrieve data.');
}
})
 
});
 
V.on("payment.cancel", function(payment)
{alert(JSON.stringify(payment)); });
V.on("payment.error", function(payment, error)
{alert(JSON.stringify(error)); });
 
 
3 REPLIES 3
Visa Dev Moderator

Re: Visa checkout integration Angular 6 with type script

Hello,

 

We are looking into the below issue and will keep you posted soon.


Thanks,

Jai

Visa Dev Moderator

Re: Visa checkout integration Angular 6 with type script

Hi,

Since this involves a lot of back and forth troubleshooting, please reach out to Visa Checkout team @ developer-support@mail.digital.visa.com directly.

 

Thanks,

Jai

Helper

Re: Visa checkout integration Angular 6 with type script

Since  no solution has been posted to this request, I wanted to post the following approach:

 

JavaScript code can be loaded to your Angular component view dynamically. This is important because you will likely want to include multiple payment methods in the same Checkout page. With this in mind, the idea is to load the VISA Checkout JavaScript code only when VISA Checkout is selected by the consumer as the payment method.

Create a loader service[1] (e.g. dynamic-script-loader.service.ts) as the one below:

 

import { Injectable } from '@angular/core';

 

interface Scripts {

  name: string;

  src: string;

  DOMElement: string;

}

 

export const ScriptStore: Scripts[] = [

/*

  For production use, the path to the VISA JavaScript Library (sdk.js) is as follows:

  { name: 'visa', src: 'https://assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js'},

*/

  { name: 'athmovil', src: 'https://www.athmovil.com/api/js/athmovil.js', DOMElement: 'head'},

  { name: 'initVISA', src: '../assets/js/initVISA.js', DOMElement: 'head'},

  { name: 'visa', src: 'https://sandbox-assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js', DOMElement: 'body'},

  { name: 'initGPay', src: '../assets/js/initGPay.js', DOMElement: 'head'},

  { name: 'hostedGPay', src: 'https://pay.google.com/gp/p/js/pay.js', DOMElement: 'head'},

  { name: 'initGPayClient', src: '../assets/js/initGPayPaymentsClient.js', DOMElement: 'head'}

];

 

declare var document: any;

 

@Injectable()

export class DynamicScriptLoaderService {

  public onLoadObject: any;

  private scripts: any = {};

 

  constructor() {

    ScriptStore.forEach((script: any) => {

      this.scripts[script.name] = {

        loaded: false,

        src: script.src,

        DOMElement: script.DOMElement

      };

    });

  }

 

  load(...scripts: string[]) {

    const promises: any[] = [];

    scripts.forEach((script) => promises.push(this.loadScript(script)));

    return Promise.all(promises);

  }

 

  loadScript(name: string) {

    return new Promise((resolve, reject) => {

      if (!this.scripts[name].loaded) {

        //load script

        let script = document.createElement('script');

        script.type = 'text/javascript';

        script.src=this.scripts[name].src;

        if (script.readyState) {  //IE

            script.onreadystatechange = () => {

                if (script.readyState === "loaded" || script.readyState === "complete") {

                    script.onreadystatechange = null;

                    this.scripts[name].loaded = true;

                    resolve({script: name, loaded: true, status: 'Loaded'});

                }

            };

        } else {  //Others

            script.onload = () => {

                this.scripts[name].loaded = true;

                resolve({script: name, loaded: true, status: 'Loaded'});

            };

        }

        script.onerror = (error: any) => resolve({script: name, loaded: false, status: 'Loaded'});

        document.getElementsByTagName(this.scripts[name].DOMElement)[0].appendChild(script);

      } else {

        resolve({ script: name, loaded: true, status: 'Already Loaded' });

      }

    });

  }

 

}

 

I have included a DOMElement parameter in order to control where the target script is inserted in the DOM. Remember that VISA Checkout instructs you to insert the onVisaCheckoutReady JavaScript function inside the <head> element of your Checkout page while the skd.js should be inserted at the end of the body.

In your Checkout component (e.g., checkout.component.ts), import your service:

Example:

import { DynamicScriptLoaderService } from '../dynamic-script-loader.service';

 

Include the service in the constructor:

constructor( private dynamicScriptLoader: DynamicScriptLoaderService ) {}

 

In order to have the flexibility of loading different JavaScript code depending on the payment method selected by the consumer, create a script-loading method in our Checkout component like the one below. The selected method will dependent on a “methodKey”.

 

private loadPaymentMethodScript(methodKey) {

// You can load multiple scripts by just providing the key as argument into load method of the service

  this.dynamicScriptLoader.load(methodKey).then(data => {

  // Script Loaded Successfully

  })

  .catch(

    error => {

      this.scriptLoadError = true;

      console.log('ERROR while loading '+methodKey);

      console.log(error)

    }

  );

}

 

I use a credit an array of card objects to keep track of the selection and loading status of different payment methods:

class creditCard {

  id: string;

  selectStatus: boolean = false;

  scriptsLoaded: boolean = false;

}

 

initpaymentMethod() {

  this.paymentMethod = new Array<creditCard>();

  for (var i=0; i <= 3 ;i++) {

    var card = new creditCard;

    this.paymentMethod.push(card);

  }

  this.paymentMethod[0].id = "VISA";

  this.paymentMethod[1].id = "ATHMovil";

  this.paymentMethod[2].id = "AMEX";

  this.paymentMethod[3].id = "GooglePay";

}

 

I call the above method from ngOnInit.

 

ngOnInit() {

  this.initpaymentMethod();

}

 

You should build your own logic between your checkout component code and the associated html template in order to tell your component which of the payment methods was selected by the consumer. This should be done BEFORE ATTEMPTING TO LOAD any JavaScript code from either Visa Checkout or any other of the available methods offered by you. You can build the component property that stores this information any way you want. In my case I decided to store it in the object array that I mention above.

 

Once the payment method is selected, you allow your consumer to use a button that invokes the script loader:

 

  <button (click) = proceedWithPmtMethod()>OK</button>

 

  proceedWithPmtMethod(){

    this.scriptLoadError = false;

    let selectedPaymentMethod = this.getSelectedPaymentMethod();

    switch (selectedPaymentMethod) {

      case 'VISA':

        console.log('Loading visa ...')

        this.loadPaymentMethodScript('initVISA');

        this.loadPaymentMethodScript('visa');

        if (!this.scriptLoadError) { this.setLoadedScriptStatus(selectedPaymentMethod) }

        break;

      case "GooglePay":

        this.loadPaymentMethodScript('initGPay');

        this.loadPaymentMethodScript('hostedGPay');     

        if (!this.scriptLoadError) { this.setLoadedScriptStatus(selectedPaymentMethod) }

        break;

      case "ATHMovil" :

        this.loadPaymentMethodScript('athmovil');

        if (!this.scriptLoadError) { this.setLoadedScriptStatus(selectedPaymentMethod) }

        break;

    }

    this.scriptLoadError = false;

  }

 

 

getSelectedPaymentMethod(): string {

  let rvalue = 'none';

  let selectedCount = 0;

  let currentID;

  for (var i = 0; i < this.paymentMethod.length ; i++) {

    if (this.paymentMethod[i].selectStatus) {

      selectedCount++;

      currentID = this.paymentMethod[i].id;

    }

  }

  if (selectedCount == 1) {

    rvalue = currentID;

  }

  return rvalue;

}

 

Notice that the id property on every creditCard object holds a key that is used to direct proceedWithPmtMethod in selecting any number of scripts to load. In the case of VISA Checkout, there are two scripts. Remember that those scripts are listed in your loader service (dynamic-script-loader.service.ts) and that the loader picks them from the ScriptStore using the name parameter.

 

You may pass the payment request object to the onVisaCheckoutReady function by first inserting it in the DOM.

In the following example, a hidden input field is used:

<input type="hidden" id="ffpr_id" value='{{getPR()}}'>

 

getPR(){

  let sPRValue = JSON.stringify(this.VParam);

  return sPRValue;

}

 

In order to test this, include a function right after the onVisaCheckoutReady function that returns the payment request JSON object to the V.init function.

 

function onVisaCheckoutReady() {

  V.init( pr() );

  V.on("payment.success", function(payment) {

    document.write("payment.success: \n" + JSON.stringify(payment));

  });

  V.on("payment.cancel", function(payment) {

    document.write("payment.cancel: \n" + JSON.stringify(payment));

  });

  V.on("payment.error", function(payment, error) {

    document.write("payment.error: \n" +

    JSON.stringify(payment) + "\n" +

    JSON.stringify(error));

  });

}

function pr() {

  let sPRValue = document.getElementById("ffpr_id").value

  prvalue = JSON.parse(sPRValue);

  return prvalue;

};

 

I hope this solution helps Angular developers working with VISA Checkout integration. If anyone makes any improvement to this solution, please let us know.

 

Regards,

Freddie A. García-Nieves

 

 

References:

1) Z. Zafar;"Angular: Load External JavaScript File Dynamically";medium.com/Better Programming;Jul 17,...