Sorry I am a beginner with jQuery and Javascript. I want to be able to get the results into my modal from any form on the page that has class ajax. My code is below but not working correctly. Currently it opens the post result in a new page and not in the modal. Can anyone shed any light on my code?
Many thanks
$(document).ready(function() {
$('.ajax').click(function() {
var that = $(this),
url = that.attr('action'),
type = that.attr('method'),
data = {};
that.find('name').each(function(index, value) {
var that = $(this),
name = that.attr('name'),
value = that.val();
data[name] = value;
});
console.log(value);
// AJAX request
$.ajax({
url: url,
type: type,
data: data,
success: function(response){
// Add response in Modal body
$('.modal-body').html(response);
// Display Modal
$('#aaModal').modal('show');
}
});
});
});
This probably happens because your browser submits the form by default. It doesnt know youre doing AJAX stuff. To prevent this, use preventDefault().
In addition to that, jQuery has a built in function for serializing (1 and 2) form data.
$(document).ready(function() {
$('form.ajax').click(function(event) {
event.preventDefault(); // prevents opening the form action url
var $form = $(this),
url = $form.attr('action'),
type = $form.attr('method'),
data = $form.serialize();
// console.log(value); // value doesnt exist outside of your loop btw
// AJAX request
$.ajax({
url: url,
type: type,
data: data,
success: function(response){
// Add response in Modal body
$('.modal-body').html(response);
// Display Modal
$('#aaModal').modal('show');
}
});
});
});
Also, its not quite clear if you bind the click event handler to a form or a button, I guess the first one. You should change the handler to the following:
$(document).ready(function() {
$('form.ajax').on('submit', function(event) {
Related
I have an email sign-up form on a website.
The form appears in two areas of each web page: the header and the footer
It's the same exact form, just available on the top and bottom of the page for better UX and accessibility.
The form uses a jQuery/AJAX script to provide success and error responses to the user. (i.e., "Success! Your subscription is complete." and "Error. Please review and re-submit")
The problem I'm having is that the header form processes but the footer form does not.
Any ideas what's wrong with this code? Thanks.
P.S. The form was working perfectly when the header and footer forms each had their own script. The problem started when the scripts were consolidated into one file. I've posted the original scripts at the bottom. Also, nothing has been changed in the PHP, so I don't think the problem is there.
$(function() {
// get the forms
var form = $('#header-form, #footer-form');
// set up event listener
$(form).submit(function(e) {
// disable html submit button
e.preventDefault();
// get the submit button
var submitButton = $('[type=submit]', this);
// get the messages element
var formResponses = $('#header-form-responses, #footer-form-responses', this);
formResponses.text(" ");
// serialize form data
var formData = $(form).serialize();
// disable submit button to prevent unnecessary submission
submitButton.attr('disabled', 'disabled');
// tell users that form is sending
submitButton.text('Processing...');
// submit form via AJAX
$.ajax({
type: 'POST',
url: $(form).attr('action'),
data: formData
})
.done(function(response) {
// make sure formResponses element has 'success' class
$(formResponses).removeClass('error');
$(formResponses).addClass('success');
// set message text
$(formResponses).text('Your subscription is complete. Thank you!');
// clear form
$('input').val('');
})
.fail(function(data) {
// make sure formResponses element has 'error' class
$(formResponses).removeClass('success');
$(formResponses).addClass('error');
// set the message text
$(formResponses).text('Input error. Please review and re-submit.');
})
.always(function(data) { // this will always fire even if the request fails
submitButton.removeAttr('disabled');
submitButton.text('Send');
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- simplified HTML -->
<form action="form_processing.php" method="post" id="header-form">
<input type="email" name="email_subscription">
<button type="submit" id="header-form-submit">Submit</button>
<div id="header-form-responses"></div>
</form>
<form action="form_processing.php" method="post" id="footer-form">
<input type="email" name="email_subscription">
<button type="submit" id="footer-form-submit">Submit</button>
<div id="footer-form-responses"></div>
</form>
Here's the original header code (works perfectly):
$(function() {
var form = $('#header-form');
var formResponses = $('#header-form-responses');
var submitButton = $("#header-form-submit");
$(form).submit(function(e) {
e.preventDefault();
var formData = $(form).serialize();
submitButton.attr('disabled', 'disabled');
submitButton.text('Processing...');
$.ajax({
type: 'POST',
url: $(form).attr('action'),
data: formData
})
.done(function(response) {
$(formResponses).removeClass('error');
$(formResponses).addClass('success');
$(formResponses).text('Your subscription is complete. Thank you!');
$('input').val('');
})
.fail(function(data) {
$(formResponses).removeClass('success');
$(formResponses).addClass('error');
$(formResponses).text('Input error. Please review and re-submit.');
}).always(function(data) {
submitButton.removeAttr('disabled');
submitButton.text('Send');
});
});
});
Here's the original footer code (works perfectly):
$(function() {
var form = $('#footer-form');
var formResponses = $('#footer-form-responses');
var submitButton = $("#footer-form-submit");
$(form).submit(function(e) {
e.preventDefault();
var formData = $(form).serialize();
submitButton.attr('disabled', 'disabled');
submitButton.text('Processing...');
$.ajax({
type: 'POST',
url: $(form).attr('action'),
data: formData
})
.done(function(response) {
$(formResponses).removeClass('error');
$(formResponses).addClass('success');
$(formResponses).text('Subscription complete.');
$('input').val('');
})
.fail(function(data) {
$(formResponses).removeClass('success');
$(formResponses).addClass('error');
$(formResponses).text('Input error. Please review and re-submit.');
}).always(function(data) {
submitButton.removeAttr('disabled');
submitButton.text('Send');
});
});
});
Within the $(form).submit( you're still using $(form), eg
var formData = $(form).serialize();
as form = $('#header-form, #footer-form') any call to $(form) (or just form) will affect/apply to/read from both forms. This depends on what the call is, eg form.attr("action") will always get the action from the first form.
Within the handler, change all $(form) (or just form) to $(this):
var formData = $(this).serialize();
...
url: $(this).attr('action'),
be careful using this inside a callback, so if you do need the relevant form then instead, change to
$('#header-form, #footer-form').submit(function(e) {
var form = $(this);
and continue to use form.
Note that in your code form is already a jquery object, but jquery allows you to "double wrap" - ie $(form) is the same as $($(form))
I recommend you remove the outer form variable completely, ie change to
// set up event listener
$('#header-form, #footer-form').submit(function(e) {
which will help to remove the issue of using form not meaning this form.
I have a button by where onclick i am trying to send the form data to the server page to process. but somehow the formdata is going empty
can anyone guide what i am doing wrong here, here is my code
function ajax(obj) {
alert('hello');
console.log(obj);
var form = document.querySelector('form');
var data = new FormData(form);
var post_url = $('#formid').attr("action"); //get form action url
var form_data = $('#formid').serialize() & '&yes=1'; //Encode form elements for submission
console.log(form_data);
console.log(data);
$.post(post_url, form_data, function( response ) {
$("#results").html(response);
});
return false;
}
the function ajax is called on the button click inside a form
You are using post menthod wich gets params in body serilliazing the args like that is good for GET request you should send in body just use a object holding all the info
$.ajax({
type: "POST",
url: url,
data: data ,// object
success: success,
dataType: dataType
});
I would like to validate a form with an AJAX request to the server and then swap the form html in the web browser with the form html from the server because this would be an easy implementation in theory. It is proving a nightmare though because the change event is triggered without the user interacting further after the first interaction which triggered the first change event. Consequently an infinite loop of AJAX requests to the server is happening.
The html form sits inside a div which has classes 'container mb-4'. This is the JS code -
var _cont = $('.container.mb-4')
var _form = $('.custom-form')
function ajax_validation(form) {
form.on('change', 'input, select, textarea', function() {
form_data = form.serialize()
$.ajax({
url: "/form/6/",
type: "POST",
data: form_data,
success: function(data) {
if(!(data['success'])) {
_cont.empty()
_cont.append(data['form_html'])
form = _cont.find('form')
ajax_validation(form)
}
},
error: function () {
form.find('.error-message').show()
}
});
})
}
ajax_validation(_form)
The change event I am assuming is triggered because the server returns a form input field with a different csrf token as the value to the previous input field - all other fields are the same. So an obvious solution would be to keep the same csrf token. But I want to understand why the JS code isn't working. I thought destroying the form would destroy the change event bound to it. So am at a loss to explain this infinite loop. How do I change this so I can just swap the form and not trigger another change event until the user really does change something?
It's not a good thing to use events in function no need to do that
Also your event here for input , select , textarea for serialize you need to select the closest() form
Try the next code
var _cont = $('.container.mb-4');
var _form = $('.custom-form');
_cont.on('change', 'form input,form select,form textarea', function() {
var ThisForm = $(this).closest('form');
var form_data = ThisForm.serialize();
$.ajax({
url: "/form/6/",
type: "POST",
data: form_data,
success: function(data) {
if(!(data['success'])) {
_cont.html(data['form_html']);
}
},
error: function () {
ThisForm.find('.error-message').show()
}
});
});
And logically if(!(data['success'])) { should be if(data['success']) {
First let's understand the issue that you have. You have a function called ajax_validation that is defining a change event on the form's elements which, on response will call ajax_validation. So, if any change happens on your elements, then a new request is sent to the server. So, if any value is changed, like a token, the request will be sent again. You could use a semaphore, like this:
var semaphore = true;
function ajax_validation(form) {
form.on('change', 'input, select, textarea', function() {
if (!semaphore) return;
semaphore = false;
form_data = form.serialize()
$.ajax({
url: "/form/6/",
type: "POST",
data: form_data,
success: function(data) {
if(!(data['success'])) {
_cont.empty()
_cont.append(data['form_html'])
form = _cont.find('form')
ajax_validation(form)
}
semaphore = true;
},
error: function () {
form.find('.error-message').show()
}
});
})
}
Something like this should solve your issue for the time being, but you should consider refactoring your code, because what you experience is well-known and is called callback hell.
Turns out the password field was coming back blank from the server - this django must do out of the box if the PasswordInput widget is used. So the form is replaced with a new form which lacks the password input from the before. The browser was then applying the autofill password value to the form which was triggering the change event.
This is my code now. It checks that the form_data about to be sent for validation really is different to before minus the csrf token which will be different.
It is based on Mohamed's answer -
var _cont = $('.container.mb-4');
var _form = $('.custom-form');
var prev_data = undefined
_cont.on('change', 'form input,form select,form textarea', function() {
var ThisForm = $(this).closest('form');
var form_data_wo_csrf = ThisForm.find("input, textarea, select").not("input[type='hidden']").serialize()
if(form_data_wo_csrf == prev_data) {
return
}
var form_data = ThisForm.serialize()
$.ajax({
url: "/form/6/",
type: "POST",
data: form_data,
success: function(data) {
if(!(data['success'])) {
_cont.html(data['form_html']);
prev_data = form_data_wo_csrf
}
},
error: function () {
ThisForm.find('.error-message').show()
}
});
});
within the form element I send data with a href. Using the JavaScript (as defined below), it works perfectly.
I want to send the forms now with Ajax, unfortunately it does not work. Do you have a solution for me. jQuery is included on the page.
Thank You!
function sendData(sFm, sID, sFn, sCl) {
var form = document.getElementById(sFm);
form.sid.value = sID;
form.fnc.value = sFn;
form.cl.value = sCl;
form.submit();
}
Send Data
My new Code:
function sendData(sFm, sID, sFn, sCl) {
var form = $("#"+sFm);
form.submit( function() {
var sid = $('input[name="sid"]').val(sID);
var fnc = $('input[name="fnc"]').val(sFn);
var cl = $('input[name="cl"]').val(sCl);
$.ajax({
type: form.attr('method'),
url: form.attr('action'),
data: {sid: sid, fnc: fnc, cl: cl}
}).done(function( e ) {
});
});
form.submit();
}
$("form").submit(function() { // for all forms, if you want specially one then use id or class selector
var url = $(this).attr('action'); // the script where you handle the form input.
var method = $(this).attr('method');
$.ajax({
type: method,
url: url,
data: $(this).serialize(), // serializes the form's elements.
success: function(data)
{
alert(data); // handle response here
}
});
return false; // avoid to execute the actual submit of the form.
});
:) , Thanks
Just because we don't want to submit all form by ajax so we can set a data-attribute to form tag to indicate, will it should be submit by ajax or normally ,, so ,,
$("form").submit(function() { ...
if($(this).attr('data-ajax') != "true") return true; // default hanlder
...
so If form is written like this :-
<form action="/dosomething" method="post" data-ajax="true"> </form> // will be sumit by ajax
<form action="/dosomething" method="post" data-ajax="false"> </form>
// will be sumit by default method
This is very consistent, but firebug is showing that my saveForm function is not being defined form my 'button.save' event handler, but it works for my 'button.deleteForm' event handler:
function saveForm(form)
{
var $form = form;
var url = $form.attr('action');
$.ajax({
type: "POST",
enctype: 'mutipart/form-data',
url: url,
data: $form.serialize(), // serializes the form's elements.
success: function(data)
{
// data is the server response.
// change this function to tell the
// user whether their submission
// is correct or what fields have
// bad data.
var response = JSON.parse(data);
return true;
}
});
return false; // avoid to execute the actual submit of the form.
}
// Do not use event handlers like .click(). This is the
// only viable solution for handling events on dynamically
// generated HTML elements. This handles the saving of data
// to the server.
$(document).on('click', 'button.save', function(e){
var $form = $(this).closest('form');
saveForm(form);
});
// This event handler is responsible for deleting data.
// For Joey's job: Please make sure that this calls save
// after the user hits delete. This will save the data in
// the database.
$(document).on('click', 'button.deleteForm', function(e){
// Get the form to update before deleting our embedded form
var $form = $(this).closest('form');
var str = $(this).attr('id');
// Get the table id in review to delete
var deleteForm = str + '_review';
$('table#' + deleteForm).remove();
// Get the collection form id to delete
var idArray = str.split('_');
idArray.pop();
divId = '#' + idArray.join('_');
$(divId).remove();
saveForm($form);
});
you missed $ in saveform
$(document).on('click', 'button.save', function(e){
var $form = $(this).closest('form');
saveForm($form);
//------^----here
});