Braintree JSv3 payment_method_nonce Value Bad With HostedFields - javascript

I have looked at a few posts on here with the same issue but under different circumstances that don't supply me with an answer to my particular issue...
I was using Braintree JSv2 with my Django project and all was working fine. Since I have migrated over to v3 of Braintree, the only issue I seem to have right now is that the value inputted to "payment_method_nonce" is not there...
Here is the code that is supposed to be dumping the payment_method_nonce value:
document.querySelector('input[name="payment_method_nonce"]').value = payload.nonce;
And here is the code that is supposed to be grabbing it on the python side:
client_payment_nonce = request.POST['payment_method_nonce']
When submitting this in my dev environment, I get an error (MultiValueDictKeyError) for "payment_method_nonce".
I am using Django 1.9 and Python 2.7. I am also using the example given by Braintree for a simple integration using HostedFields...
Small test
So I manually added an input field in my form with name "payment_method_nonce" just to see if not having a field was causing some issue. I know it is injected by Braintree but just testing a thought. It seems that although the value of payment_method_nonce is supposed to be my nonce, I didn't type anything into the input box and it was still coming back as null.
Full Snippets of Form and HostedFields
<form action="/booking/" method="post" id="checkout_form">
{% csrf_token %}
<div class="payment">
<span>Payment</span>
<!--input elements for user card data-->
<div class="hosted-fields" id="card-number"></div>
<div class="hosted-fields" id="postal-code"></div>
<div class="hosted-fields" id="expiration-date"></div>
<div class="hosted-fields" id="cvv"></div>
<div class="btns">
<input type="hidden" name="payment_method_nonce">
<input type="submit" value="Complete Booking" id="pay-button">
</div>
</div>
</form>
Note: I had just changed the payment_method_nonce field to type="hidden" instead of type="text" but still have the same effect...
<!-- load the required client component -->
<script src="https://js.braintreegateway.com/web/3.15.0/js/client.min.js"></script>
<!-- load the hosted fields component -->
<script src="https://js.braintreegateway.com/web/3.15.0/js/hosted-fields.min.js"></script>
<!-- Braintree setup -->
<script>
var client_token = "{{ request.session.braintree_client_token }}"
var form = document.querySelector('#checkout-form');
var submit = document.querySelector('input[type="submit"]');
braintree.client.create({
authorization: client_token
}, function (clientErr, clientInstance) {
if (clientErr) {
// Handle error in client creation
return;
}
braintree.hostedFields.create({
client: clientInstance,
styles: {
'input': {
'font-size': '14px'
},
'input.invalid': {
'color': 'red'
},
'input.valid': {
'color': 'green'
}
},
fields: {
number: {
selector: '#card-number',
placeholder: 'Credit Card Number'
},
cvv: {
selector: '#cvv',
placeholder: '123'
},
expirationDate: {
selector: '#expiration-date',
placeholder: '10/2019'
},
postalCode: {
selector: '#postal-code',
placeholder: '10014'
}
}
}, function (hostedFieldsErr, hostedFieldsInstance) {
if (hostedFieldsErr) {
// handle error in Hosted Fields creation
return;
}
submit.removeAttribute('disabled');
form.addEventListener('submit', function (event) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (tokenizeErr, payload) {
if (tokenizeErr) {
// handle error in Hosted Fields tokenization
return;
}
// Put `payload.nonce` into the `payment_method_nonce`
document.querySelector('input[name="payment_method_nonce"]').value = payload.nonce;
document.querySelector('input[id="pay-button"]').value = "Please wait...";
form.submit();
});
}, false);
});
});
</script>
Note: the line document.querySelector('input[id="pay-button"]').value = "Please wait..."; doesn't fire (I know this because the button does not change values). Maybe these querySelector lines just aren't working?
Something New Noticed
I just went back to my page and hit the submit button without even entering any information. In v2 of Braintree, I would not be able to click the submit button until all fields were filled in... Maybe the values in my form aren't even being sent to braintree to receive a nonce and that's why there is an empty string being returned..?

Moral of the story
Review your code... Multiple times. As pointed out by C Joseph, I have my form ID as something different than what my var form is referencing...
<form action="/booking/" method="post" id="checkout_form">
var form = document.querySelector('#checkout-form');

Related

Bootstrap V5 Form Validation & Sweetalert2 : Showing success message after successful submission

I have simple form based on Bootstrap 5 with a validation option I'm trying to display alert message if the form field is successfuly submited using Sweatalert2.
Here is my Code :
HTML
<form action="" method="POST" class="needs-validation" novalidate>
<label for="validationCustomUsername" class="form-label">Username</label>
<div class="input-group has-validation mb-3">
<span class="input-group-text" id="inputGroupPrepend">#</span>
<input type="text" class="form-control" id="validationCustomUsername" placeholder="Username *" aria-describedby="inputGroupPrepend" required />
<div class="invalid-feedback">
Please choose a username.
</div>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
JS
(function () {
'use strict'
// Fetch all the forms we want to apply custom Bootstrap validation styles to
var forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.prototype.slice.call(forms)
.forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
}, false)
})
})()
Live Example
I was having the same issue and came across this post which quite helpful.
Below code might help:
......
form.classList.add('was-validated');
if (form.reportValidity()) {
event.preventDefault()
Swal.fire({
position: 'center',
icon: 'success',
title: 'Your application has been submitted successfully!',
showConfirmButton: false,
timer: 2500
}).then((result) => {
// Reload the Page
location.reload();
});
}
It will reload the page after form submission.
This is may be too late, but I hope it can help others. I have the same issue. Then, I tried to combine bootstrap validation inside the SweetAlert Confirmation Box before submitting the form.
I create the code like below:
$('#submitForm').on('click', function (e) {
e.preventDefault();// prevent form submit
/*this part is taken from bootstrap validation*/
var forms = document.getElementsByClassName('needs-validation');
var validation = Array.prototype.filter.call(forms, function (form) {
if (form.checkValidity() === false) {
form.classList.add('was-validated');
}
else {
Swal.fire({
title: 'Are you sure?',
text: "It cannot be undone",
type: 'warning',
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, send it!'
}).then((result) => {
if (result.value) {
/*submit the form*/
$("#formsubmitsekali").submit();
}
});
}
}, false);
});
submitForm is the ID name for the button ID for submit the form.
formsubmitsekali is the form ID.
By doing so, if the required field is not filled, it will show the bootstrap validation without showing Sweetalert confirmation box. But if all of required fields are filled, the Sweetalert will show up.
The same behavior also happens if you have email input type, but it is filled by non-email, it will run the bootstrap validation first. It is also work if you use HTML5 pattern inside the input type and the user fills with the wrong pattern.

How do I make a submit button using devexpress and knockout.js?

So I have an app that shows expenses of a person. I made the view to add a new expense, but I don't know how to make the save button so it saves the expense in the db and redirects to the list of expenses.
The view has many fields like this:
<div id="selBxChSt" data-bind="dxLookup: {
dataSource: dsExpenses,
valueExpr: 'NAME',
displayExpr: 'NAME',
title: 'Expense',
searchEnabled: true,
value: selectedExpense
}">
</div>
And not only dxLookup, also dxTagBox,dxDateBox and dxTextArea.
I made the reset button, to set all fields to their default value. But I don't know how to save them to the firebird db.
This is the html for the button:
<div class="Column" data-bind="dxButton: {icon: 'todo', text: 'Save', type: 'normal', onClick: expenseSave}"></div>
So now I have to make a function in knockoutJS to save all the things the user chooses from the lookups.
I have no idea how to do this, I'm new to knockout.js and devexpress, so any idea or tips would be amazing, thank you!
To implement "old-school" form that submits data to a server-side go this way:
Wrap all editors and submit button with the form tag.
Use the useSubmitBehavior option for dxButton.
Set the name option for editors.
Your code should be like below:
<form action="your-action" method="post" data-bind="event: { submit: onFormSubmit }">
<div data-bind="dxTextBox: { name: 'login' }"></div>
<!-- other editors... -->
<div data-bind="dxButton: { text: 'Submit', useSubmitBehavior: true }"></div>
</form>
View model:
viewModel.onFormSubmit = function() {
// Here you can implement a custom logic before submit. Validate editors, for instance.
};
Refer this sample, as well.

Braeintree Client Set Up with JS v3 - payment_method_nonce null and the form isn't submitting

I've tried to integrate Braintree in my Laravel 5.2 app and everything works fine with JS v2 client setup, but I would like to upgrade it to v3.
This is from the docs (I've customized a bit):
<form id="checkout-form" action="/checkout" method="post">
<div id="error-message"></div>
<label for="card-number">Card Number</label>
<div class="hosted-field" id="card-number"></div>
<label for="cvv">CVV</label>
<div class="hosted-field" id="cvv"></div>
<label for="expiration-date">Expiration Date</label>
<div class="hosted-field" id="expiration-date"></div>
<input type="hidden" name="payment-method-nonce">
<input type="submit" value="Pay">
</form>
<!-- Load the Client component. -->
<script src="https://js.braintreegateway.com/web/3.0.0-beta.8/js/client.min.js"></script>
<!-- Load the Hosted Fields component. -->
<script src="https://js.braintreegateway.com/web/3.0.0-beta.8/js/hosted-fields.min.js"></script>
<script>
var authorization = '{{ $clientToken }}'
braintree.client.create({
authorization: authorization
}, function (clientErr, clientInstance) {
if (clientErr) {
// Handle error in client creation
return;
}
braintree.hostedFields.create({
client: clientInstance,
styles: {
'input': {
'font-size': '14pt'
},
'input.invalid': {
'color': 'red'
},
'input.valid': {
'color': 'green'
}
},
fields: {
number: {
selector: '#card-number',
placeholder: '4111 1111 1111 1111'
},
cvv: {
selector: '#cvv',
placeholder: '123'
},
expirationDate: {
selector: '#expiration-date',
placeholder: '10 / 2019'
}
}
}, function (hostedFieldsErr, hostedFieldsInstance) {
if (hostedFieldsErr) {
// Handle error in Hosted Fields creation
return;
}
form.addEventListener('submit', function (event) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (tokenizeErr, payload) {
if (tokenizeErr) {
// Handle error in Hosted Fields tokenization
return;
}
document.querySelector('input[name="payment-method-nonce"]').value = payload.nonce;
form.submit();
});
}, false);
});
});
</script>
But when I click the submit button, nothing happens.event.preventDefault() stops the submission and the payment_method_nonce token is generated, but I can't submit the form after that, because form.submit() isn't works
How can I submit the form after event.preventDefault()?
Or how can I send the payment_method_nonce token to my controller?
Thanks!
When I copied your snippet and tried to run the example, I got (index):69 Uncaught ReferenceError: form is not defined in the console. When I added
var form = document.getElementById('checkout-form');
it worked just fine.
Best guess, you just forgot to assign the form variable to reference the form dom element. If that's not the case, be sure to let me know.

How to add two inputs from the same forms in the same collection field in Meteor?

Im working on the tutorial meteor has for my first app. So i wanted to extend it a bit more and have two text boxes, one for comments and one for rating lets say.
The problem is that i cant get correctly the values from both forms (actually cant get the rating value at all) in order to save them in my database and furthermore the enter-submit feature stopped working.
My .js code for body events is:
Template.body.events({
"submit .new-task": function(event) {
// Prevent default browser form submit
event.preventDefault();
// Get value from form element
var text = event.target.text.value;
var rating = event.target.rating.value;
// Insert a task into the collection
Meteor.call("addTask", text, rating);
// Clear form
event.target.text.value = "";
}
});
For add task:
AddTask: function(text, rating) {
//.....
Tasks.insert({
text: text,
createdAt: new Date(),
owner: Meteor.userId(),
username: Meteor.user().username,
rating: rating
});
}
And my HTML:
<form class="new-task">
<h2>What is happening?</h2>
<input type="text" name="text" placeholder="Share your experience!" />
<h2>Rating:</h2>
<input type="text" name="rating" placeholder="insert your rating!" />
</form>
<template name="task">
<li class="{{#if checked}}checked{{/if}}">
{{#if isOwner}}
<button class="delete">×</button>
{{/if}}
<span class="text"><strong>{{username}}</strong> - {{text}}- {{rating}}</span>
</li>
</template>
Your Meteor method addTask is not defined. Call Meteor.call("AddTask", text, rating); instead, or rename your method to addTask.
For example:
if (Meteor.isClient) {
Template.hello.events({
'click button': function () {
Meteor.call("addTask", "1", 2, function(error){
if (error) alert(error.reason);
});
}
});
}
if (Meteor.isServer) {
Meteor.methods({
addTask: function (text, rating) {
check(text, String);
check(rating, Number);
console.log(text);
console.log(rating);
}
});
}

Meteor.js Validation w/ Mesosphere

I'm trying to implement Mesosphere for validation into my meteor app but it seems like Mesosphere isn't picking up on some of the native validations I've listed.
I tried just a single validation for formatting of email and it's required length. For example:
Mesosphere({
name: 'signupForm',
method: 'signupUser',
fields: {
email: {
required: true,
format: 'email',
rules: {
exactLength: 4
},
message: 'Wrong length'
}
},
onFailure: function (errors) {
messages = [];
messages = _.map(errors, function (val, err) {
console.log(val.message);
});
},
onSuccess: function (data) {
alert("Totally worked!")
}
});
The 'onFailure' (and onSuccess) callback seems to work because it is logging something when I submit the form. Which makes me believe I have it set up properly on the form submit event too. There you pass the form object to Mesosphere to create the validationObject if I understand it correctly. For example:
var validationObject = Mesosphere.signupForm.validate(accountData);
Once submitted, it's logging Field Required as the error which is weird because I did type something into the field. It makes no mention of an incorrect length or format. It skips the 'Wrong Length' message and I can't find that message in the object anywhere.
So my question is what am I doing wrong to not be getting the proper message for the incorrect input for that form field? Thanks : )
Also, willing to take recommendations on other validation packages. Mesosphere leverages Meteor's server/client features for validation so it seemed like a good place to start.
Template:
<template name="signup">
<form name="signupForm" id="signup-form" class="panel" action="#">
<div class="form-group">
<label for="email">Email</label>
<input type="text" name="email" id="email" class="form-control" />
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" name="password" id="password" class="form-control" />
</div>
<div class="form-group">
<input type="submit" value="Sign Up" id="create-account" class="btn btn-success pull-right">
</div>
</form> </template>
Which calls this method in the corresponding file:
signupUser: function(accountData) {
var uid = Accounts.createUser(accountData);
}
So basically what I see here is that your rules don't reflect how the form would be validated. You have an email that must match the email format, but then you have a rule that says it has to be exactly 4 characters long.. a better field definition would look like this:
fields: {
email: {
required: true,
format: 'email',
message: 'Please enter a valid email address'
},
password: {
required: true,
rules: {
minLength: 6,
maxLength: 30,
},
message: "Password must be between 6 and 30 characters"
}
}
I created a github repo that you can clone and run to test this out if you would like.
https://github.com/copleykj/meso-test
Hope this helps.

Categories

Resources