Two forms on one page - input types transferring - javascript

I have two forms on one page to handle a choice of 2 stripe subscriptions (basic and advanced) and I'm using javascript to submit each form on click of the button as below:
For the basic plan:
<form id="payment_form_basic" action="" method="POST">
<input type="hidden" name="subscription_purchase_non_trial" value="subscription_purchase_non_trial_basic" />
<button id="pricing__action_grey">Choose Plan</button>
</form>
<script src="https://checkout.stripe.com/checkout.js"></script>
<script>
// ******************************************
// ****** Basic Plan Form Processor *********
// ******************************************
var handler = StripeCheckout.configure({
key: '<?php echo $stripe['publishable_key']; ?>',
image: 'https://example.com/example.png',
locale: 'auto',
allowRememberMe: 'false',
token: function(token) {
$('#payment_form_basic').append($('<input type="hidden" name="stripeToken" />').val(token.id));
$('#payment_form_basic').append($('<input type="hidden" name="stripeEmail" />').val(token.email));
$("#payment_form_basic").submit();
}
});
document.getElementById('pricing__action_grey').addEventListener('click', function(e) {
// Open Checkout with further options:
handler.open({
name: 'Basic',
description: 'example description',
zipCode: true,
amount: 10
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function() {
handler.close();
});
</script>
And for the advanced plan:
<form id="payment_form_advanced" action="" method="POST">
<input type="hidden" name="subscription_purchase_non_trial" value="subscription_purchase_non_trial_advanced" />
<input type="hidden" name="subscription_type" value="advanced" />
<button id="pricing__action">Choose Plan</button>
</form>
<script>
// ******************************************
// ****** Advanced Plan Form Processor ******
// ******************************************
var handler = StripeCheckout.configure({
key: '<?php echo $stripe['publishable_key']; ?>',
image: 'https://example.com/example.png',
locale: 'auto',
allowRememberMe: 'false',
token: function(token) {
$('#payment_form_advanced').append($('<input type="hidden" name="stripeToken" />').val(token.id));
$('#payment_form_advanced').append($('<input type="hidden" name="stripeEmail" />').val(token.email));
//$('#payment_form_advanced').append($('<input type="hidden" name="subscription_type" value="advanced" />'));
$("#payment_form_advanced").submit();
}
});
document.getElementById('pricing__action').addEventListener('click', function(e) {
// Open Checkout with further options:
handler.open({
name: 'Advanced',
description: 'example descript',
zipCode: true,
amount: 12
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function() {
handler.close();
});
</script>
I'm trying to use the subscription_type field in the advanced form as a switch when the page posts onto itself to determine whether to process the basic plan price or the advanced plan however the form still post the "advanced" subscription type through when the basic form is submitted, it seems like the advanced from always overwrites the basic form, at list that' what appears to happen when I print the post variables received, which makes no sense to me. Does anyone know why this is happening?

Seems I needed to wrap all the script (in each scenario) in the on click function, that way the advanced settings didn't over write the basic settings for stripe. Hopefully this is a robust approach.

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.

Add object(s) to form submission (post)

I have a form and I have two objects I want to submit with that form.
<form role="form" id="orderform" action="test.php" method="post">
<input type="text" name="test">
<button type="submit">Place Order</button>
</form>
<script>
var items1 = {name: "test", value: "123"} //needs to submit with form
var items2 = {name: "test2", value: "456"} //meeds to submit with form
$("#orderform").submit(function(event) {
event.preventDefault();
//do something to add items1 and items2 to form.
}
</script>
How do I submit items1 and items2 with the form submission?
There are already answers to this question (Adding POST parameters before submit) but I personally think that adding dom elements should not be the way to go.
My approach would be to get the form data onsubmit and add your objects to it. Afterwards send the request. The major benefits are you can make use of ajax (which in fact improves the user experience) and dont have to modify / add dom elements which can get quite nasty if you add more than 2 objects.
var items1 = {
name: "test1",
value: "123"
} //needs to submit with form
var items2 = {
name: "test2",
value: "456"
} //meeds to submit with form
$("#orderform").submit(function(event) {
event.preventDefault();
//add the items to the form data
let data = $(this).serializeArray();
data.push(items1);
data.push(items2);
let params = $.param(data);
//send the data with ajax
$.ajax({
type: $(this).attr('method'),
url: $(this).attr('action'),
data: data,
success: function(data) {
window.location.href = "success.php"+params;
},
error: function() {
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form role="form" id="orderform" action="test.php" method="post">
<input type="text" name="test">
<button type="submit">Place Order</button>
</form>
In order to show the results on a seperate page I'd add the form data as get parameters to the success redirect and show them like this.
Please also read on XSS and how to avoid it (sanitize input / parameters).
success.php should look like the following.
echo $_GET["test1"];
echo $_GET["test2"];
You can add them as hidden inputs.
let items = [
{
name: 'bar',
value: 'foo',
},
{
name: 'qux',
value: 'baz',
},
];
let form = document.getElementById('orderform');
let itemsToBeSubmited = items;
itemsToBeSubmited.forEach((item) => {
let input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', item.name);
input.setAttribute('value', item.value);
form.appendChild(input);
});
<form role="form" id="orderform" action="test.php" method="post">
<input type="text" name="test">
<button type="submit">Place Order</button>
</form>

Braintree JSv3 payment_method_nonce Value Bad With HostedFields

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');

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 charge a stripe card in meteor

Having a warm time trying to charge a card in Meteor. The error I get is: Exception while invoking method 'chargeCard' Error: Match error: Expected string, got object. I do get the modal where I typed in the email and card number but after pressing the pay button, in terminal I get the error message.
How to call the charge function properly? I cant find any tutorial that matches closely the way I implement it.
The setup is very basic. I also have jquery installed.
Template:
<template name="hello">
<form id="myForm">
<input type="text" id="amount" name="amount"/>
<input type="hidden" id="stripeToken" name="stripeToken"/>
<input type="hidden" id="stripeEmail" name="stripeEmail"/>
</form>
<hr>
<button id="customButton">Pay</button>
</template>
js:
if (Meteor.isClient) {
Template.hello.helpers({
});
Template.hello.events({
'click button': function (e) {
e.preventDefault();
var handler = StripeCheckout.configure({
key: 'pk_test_rand',
token: function(token) {
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
$("#myForm").submit();
Meteor.call('chargeCard', token); // this seem not right?
}
});
// Showing the pop up Stripe dialog
var amount = $("#amount").val() *100;
// Open Checkout with further options
handler.open({
name: 'Demo Site',
description: '2 widgets ($20.00)',
amount: amount
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
}
});
Meteor.startup(function(){
$.getScript('https://checkout.stripe.com/checkout.js', function(){
// script has loaded
});
});
}
if (Meteor.isServer) {
Meteor.methods({
'chargeCard': function(stripeToken) {
check(stripeToken, String);
var Stripe = StripeAPI('sk_test_rand');
Stripe.charges.create({
source: stripeToken,
amount: 5000, // this is equivalent to $50
currency: 'usd'
}, function(err, charge) {
console.log(err, charge);
});
}
});
}
It seems you're passing the whole token object:
Meteor.call('chargeCard', token);
But your chargeCard() method expects a string:
check(stripeToken, String);
So you need to either pass only the token id:
Meteor.call('chargeCard', token.id);
or change your chargeCard() method to expect and use the whole token object:
Meteor.methods({
'chargeCard': function(stripeToken) {
check(stripeToken, Object);
var Stripe = StripeAPI('sk_test_rand');
Stripe.charges.create({
source: stripeToken.id,
...

Categories

Resources