1

I have a dynamic AJAX submit. I am trying to submit Braintree (PayPal) payment data into payment.php using AJAX. Unfortunately, Braintree is giving me a nonce error. Braintree creates an input with a code (nonce) on submit, but my submit is submitted before the code is created.

Braintree gives me a script that creates the code

<script src="https://js.braintreegateway.com/v2/braintree.js"></script>

And I use something like

$(document).on("submit","form",function(event){
  if(!$(this).is("[action]")){
    event.preventDefault()
    formdata=new FormData(this)
    submit(this)
}

submit(this) calls the ajax. I tried to delay the submit, but then nothing works. For example. If I call an alert() during my submit, the code is added and the submit works fine; except for the fact that now I have an alert. The problem is that both codes run at the same time and the Braintree code is too slow to react. I also tried to re-position the link above and below my JS code with no luck.

halfer
  • 19,824
  • 17
  • 99
  • 186
Maciek Semik
  • 1,872
  • 23
  • 43
  • Hello Please don't us JS for to submit the payment gateway it will be easily hack instead of that use PHP Braintree library. – Mitul Sep 29 '15 at 07:21
  • How do I get validation errors without reloading page? Or must it be reloaded, no way around it? – Maciek Semik Sep 29 '15 at 07:30
  • @Mitul.. but PHP is server side script which doesn't work in our browsers. If we're to do some processing before submitting our form, then JS in the only way :) – Arkantos Sep 29 '15 at 07:32
  • You can do same with ajax call on own server and then call braintree payment method b in client side the key will be visible – Mitul Sep 29 '15 at 07:35
  • I'm having some trouble understanding your approach. Ajax is done with JS right ? If you look at the flow [here](https://developers.braintreepayments.com/javascript+ruby/start/hello-client#set-up-your-js-client), our JS client will get a token from our server which will be used for authentication with BrainTree server, get a nonce from BrainTree server, send that nonce to our server which in turn will validate that with BrainTree server again just to be sure. – Arkantos Sep 29 '15 at 07:43
  • Maybe I am having trouble understanding the process. On click, I thought I would dynamically submit a page with the data, validate it using the braintree php and return the errors via ajax dynamically without reloading page. My main task is to get errors without reloading page. If no errors, redirect successfully. How do I get errors without reloading page? – Maciek Semik Sep 29 '15 at 07:58

3 Answers3

2

As mentioned here, I think you should use onPaymentMethodReceived callback from GlobalSetup of BrainTree. Instead of handling form submit on your own using jQuery, you can configure this callback in the setup like below.

    braintree.setup("CLIENT-TOKEN-FROM-SERVER", "dropin", {
      container: "dropin-container",
      onPaymentMethodReceived: function (paymentMethod) {
        // Do some logic in here.
        // When you're ready to submit the form:
        myForm.submit();
      }
   });

The onPaymentMethodReceived is called when a payment_method_nonce has been generated by Drop-in (as the result of a form submission). It will be called with a paymentMethod object, which contains the nonce as a string.

You can find more details here about the paymentMethod object passed to onPaymentMethodReceived callback, it has a property called nonce.

Hope this helps :)

Arkantos
  • 6,530
  • 2
  • 16
  • 36
  • Thanks but I tried this. onPaymentMethodrecieved only gets received on submit. So you it prevents any other submit. submit->creates nonce->no more submit – Maciek Semik Sep 29 '15 at 07:33
  • Ya that's what we want to do right ? `onPaymentMethodReceived` will be invoked on form submit after your nonce is generated, you can get a reference to that using the object passed to this callback and after that you will manually trigger the form submit as shown in the example code above. – Arkantos Sep 29 '15 at 07:36
  • Do you only need to send the nonce to get all the errors? Does the nonce contain the error information as well? Maybe thats what I am misunderstanding – Maciek Semik Sep 29 '15 at 08:05
  • 2
    I suggest you to go through [this](https://developers.braintreepayments.com/javascript+ruby/start/overview#how-it-works) to get an understanding of how it works. You don't send a nonce to BrainTree server from your JS file, you send a Token to BrainTree server to authenticate a payment method and if it's a valid method, BrainTree server responds with a `nonce`. You then send that nonce and other payment details to your own PHP/Java server which will create a new transaction and send it to BrainTree server which will process the payment. – Arkantos Sep 29 '15 at 08:31
  • Thanks so much. Now I understand. I thought the whole form needed submission to get errors, but indeed I just needed the nonce generated. Thank you. – Maciek Semik Sep 29 '15 at 08:36
  • Glad to be of help :) In case you want to catch any errors while authenticating your client token with BrainTree server, you can use `onError` in your GlobalSetup in JS file. If there are no errors and it's a valid token, you get a nonce which can be accessed in your `onPaymentMethodReceived` callback. – Arkantos Sep 29 '15 at 08:39
0

My solution for prevent AJAX submit before nonce receiving. Hope this helps.

braintree.setup('TOKEN-HERE', "dropin", {
  container: "payment-form",
  onPaymentMethodReceived: (obj) ->
    $('form#checkout input#payment_method_nonce').val(obj['nonce'])
    frm = $('form#checkout')
    $.ajax
      type: frm.attr('method')
      url: frm.attr('action')
      data: frm.serialize()
})

$(document).on 'ajax:before', 'form#checkout', ->
  return false unless $('form#checkout input#payment_method_nonce').val()
0

I wanted to do the same and that's what I did.

  • first create the dropin and handle any creation errors till line 8 ,
  • then prevent the default submit event to get payment_method_nonce ,
  • finally use this method >> requestPaymentMethod( ) << to assign the nonce value.

that's it and don't forget to serialize the form before you send it, hope this will help you

the source code here braintree payments set up your client

var form = document.querySelector('#payment-form');
var client_token = '{{ client_token }}';
console.log(client_token)
braintree.dropin.create({
  authorization: client_token,
  container: '#bt-dropin',
  paypal: { flow: 'vault' }
  }, function (createErr, instance) {
    form.addEventListener('submit', function (event) {
      event.preventDefault();
      instance.requestPaymentMethod(function (err, payload) {
        if (err) {
          console.log('Error', err);
          return;
        }
        // Add the nonce to the form and submit
        // Submit payload.nonce to your server
        document.querySelector('#nonce').value = payload.nonce;
        //form.submit();
        submit_it(form );
      });
    });
  });


function submit_it(params) {
  params = $(params).serialize()
  $.ajax({
    type:'POST',
    url :  window.location +"checkout/",
    beforeSend: function(xhr, settings) {
      if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
        xhr.setRequestHeader("X-CSRFToken", csrftoken);
      }
    },
    data:params,
    success: function(data){
      console.log("succeded");
      console.log(data)
    },
    complete: function (xhr, textStatus) {
      console.log(xhr.status);
      if ( xhr.status == 200) {
      //complete code
      }
    },
    error:function(){
      // Do something not that success-ish
      alert( "something gone wrong" );
    }
  });
}
bob
  • 1,668
  • 1
  • 8
  • 8