Search code examples
javascriptphpjqueryhtmlbraintree

Jquery generated input values not being posted on form submit


I'm using braintree to process payments for a website that I'm creating. The api requires that I generate a payment method nonce via javascript in order to process the payment. I'm able to generate the nonce on form submit and place it in the input field however, the value is not being posted.

The jquery:

  $( document ).ready(function() {
  $('#checkout').on("submit", function() {
      var client = new braintree.api.Client({clientToken: "<?php echo $clientToken ?>"});
      client.tokenizeCard({
      number: $('#number').val(),
      cardholderName: $('#first_name').val() + ' ' + $('#last_name').val(),
      expirationMonth: $('#expiration_month').val(),   
      expirationYear: $('#expiration_year').val(),   
      cvv: $('#cvv').val(),
      }, function (err, nonce) {
      $("#checkout input[name=nonce]").val(nonce);
      $('#checkout input[name=random]').val('randomtext');
  });

      });
  });

The php:

<?php
echo $_POST['first_name'];
echo '<br/>';
echo $_POST['last_name'];
echo '<br/>';
echo $_POST['phone_number'];
echo '<br/>';
echo $_POST['expiration_month'];
echo '<br/>';
echo $_POST['expiration_year'];
echo '<br/>';
echo $_POST['nonce'];
echo '<br/>';
echo $_POST['random'];
echo '<br/>';
$result = Braintree_Transaction::sale(array(
'amount' => '113.00',
  'paymentMethodNonce' => $_POST['nonce'],
  'orderId' => 'order id',
  'customer' => array(
'firstName' => $_POST['first_name'],
'lastName' => $_POST['last_name'],
'phone' => $_POST['phone_number'],

  )

));

if ($result->success) {
print_r("success!: " . $result->transaction->id);
} else if ($result->transaction) {
print_r("Error processing transaction:");
print_r("\n  code: " . $result->transaction->processorResponseCode);
print_r("\n  text: " . $result->transaction->processorResponseText);
} else {
print_r("Validation errors: \n");
print_r($result->errors->deepAll());
}
?>

The html:

<form id="checkout" name="checkout" action="checkout_result.php" method="post" style="width:20em;font-size:1.5em;margin-left:auto;margin-right:auto;">
<table style="margin-top:0.5em;">
<tr>
<td style="padding-left:0.75em;">First Name:</td>
<td><input style="font-size:0.75em;"data-braintree-name="first_name" name="first_name"     id="first_name" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Last Name:</td>
<td><input style="font-size:0.75em;"data-braintree-name="last_name" name="last_name"    id="last_name" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Email Address:</td>
<td><input  style="font-size:0.75em;" name="email_address" id="email_address" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Phone Number:</td>
<td><input style="font-size:0.75em;" name="phone_number" id="phone_number" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Street Address:</td>
<td><input style="font-size:0.75em;" data-braintree-name="street_address" name="street_address"     id="street_address" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Apt #:</td>
<td><input style="font-size:0.75em;" data-braintree-name="extended_address" name="extended_address" id="extended_address" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Postal Code:</td>
<td><input style="font-size:0.75em;" data-braintree-name="postal_code" name="postal_code"     id="postal_code" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Card Number:</td>
<td><input style="font-size:0.75em;" data-braintree-name="number" name="number" id="number"     value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Expiration Month:</td>
<td><input style="font-size:0.75em;" data-braintree-name="expiration_month" name="expiration_month" id="expiration_month" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Expiration Year:</td>
<td><input style="font-size:0.75em;" data-braintree-name="expiration_year" name="expiration_year" id="expiration_year" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">CVV:</td>
<td><input style="font-size:0.75em;" data-braintree-name="cvv" name="cvv" id="cvv" value=""/>             </td>
</tr>
<tr>
<td style="padding-left:0.75em;">Random:</td>
<td><input style="font-size:0.75em;" name="random" id="random" value=""/></td>
</tr>
<tr>
<td style="padding-left:0.75em;">Nonce:</td>
<td><input type="text" style="font-size:0.75em;" name="nonce" id="nonce" value=""/></td>
</tr>
</table>
<div style="padding-top:0.25em;padding-bottom:0.25em;text-align:center;"><span><input     style="font-size:0.5em;" type="submit"
 id="submit" value="SUBMIT"/></span></div>
</div>

</form>

How do I get the nonce input field to post. The random text input field doesn't post either.


Solution

  • The problem is probably with the fact, that tokenizeCard makes an asynchronous call to get the nonce. The flow of events is then like this:

    submit form begins -> tokenizing begins -> submit form ends ->
    (somewhere here the promise is resolved - the result comes back from the server)
    -> tokenizing ends
    

    What you can do is to add return false to the end of submit listener (conditions by the emptiness of nonce field) and then then call submit again (without getting the nonce from server again) from the client callback. It would look like this:

    $('#checkout').on("submit", function() {
      //I could be wrong in the condition below - it may be undefined
      if($("#checkout input[name=nonce]").val() === ''){ 
        var client = new braintree.api.Client({clientToken: "<?php echo $clientToken ?>"});
        client.tokenizeCard({
          number: $('#number').val(),
          cardholderName: $('#first_name').val() + ' ' + $('#last_name').val(),
          expirationMonth: $('#expiration_month').val(),   
          expirationYear: $('#expiration_year').val(),   
          cvv: $('#cvv').val(),
        }, function (err, nonce) {
          $("#checkout input[name=nonce]").val(nonce);
          $('#checkout input[name=random]').val('randomtext');
          $('#checkout').submit();
        });
        return false; //stops form submitting
      } else {
        return true; //continues form submitting
      }
    });

    Edit: This fiddle represents your problem exactly

    $("#form").submit(function(){
        alert("submit invoked!");
        if($("#writeMe").val() === ''){
            writeValue();
            alert("submit not done - writeValue invoked");
        } else {
            alert("submit actually done");
        }
        return false;
    }); 
    
    function writeValue(){
        setTimeout(function() {
           alert("result's back -> gonna submit again");
           $("#writeMe").val("written");
           $("#form").submit(); 
        }, 1000);
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    <form id="form">
        <input type="text" readonly id="writeMe" />
        <input type="submit" value="Submit me!" />
    </form>