Submit a form without refreshing a page using ajaxForm - javascript

I'm a total novice so please excuse my ignorance.
I have website with a php shopping cart that refreshes to the cart page when something is added to to the cart. I want to modify it so that when a product is added, the cart updates in the background and the product page does not refresh but updates the html in various divs with unique id's.
I have managed to achieve this but I am sure that there must be a simpler way as my solution involves a loop that trawls through all the forms on the product page rather than just updating the divs from the form that was submitted.
Here's my JavaScript which is inside the <head> tags of the product page:
<script>
$(document).ready(function(){
$("[id^=ectform]").ajaxForm({ // any form id beginning with ectform
success:function(){
$.ajaxSetup({ cache: false });
$("#div1").load("jsrefresh.php"); // update html in div in minicart
for (i = 0; i < count; i++) { // count holds the number of forms on the page
var d = "#glc" + i; // div id to update
var f ="#gld" + i; // another div id to update
var e = eval("z" + i); // product id
$(f).html('loading...').load("jsrefreshincart.php",{ prodynum: e, divno: d});
};
}
});
});
</script>
The script utilises ajaxForm to wait for the successful submission of any form with an Id beginning with ectform. On success, The form is submitted to the cart script which updates the cart contents and then ajax .load is used to call jsrefresh.php which echoes back the updated html to a div in a mini cart which is displayed at the top of the screen. Then (this is the bit that needs doing properly) jsrefreshincart.php is called in a loop ( the variable count holds the total number of forms on the page ) which updates html in all divs within all the forms on the page with information about how many items are in the cart and how much they cost.
Is there any way of doing this without the loop as only the divs within the form that was submitted need to be updated ?

The major problem here is not that you have a loop, but that you have a server-call inside of it. The best way to handle this is to change the way that jsrefreshincart.php handles calls from the server. Instead of having multiple calls inside the loop, collect all the data and have a single call outside the loop.
I don't think that's something the jQuery Form plugin can handle; rather, you'll probably have to write some custom code (like below):
<script>
$(document).ready(function() {
$("[id^=ectform]").on('submit', function(e) {
e.preventDefault();
$('[id^=gld]').html('loading...'); // Trigger all loading messages simultaneously
var formNums = [];
for (i = 0; i < count; i++) {
formNums.push(i);
}
$.post({
$(this).attr('action'), // Where to send the form action
formNums: formNums, // The data to send when submitting the Ajax call
refreshCartData // The callback used to refresh the page
});
});
});
// Called automatically when the server responds with data
function refreshCartData(data) {
// Loop through all forms and update them
for (var i = 0; i < data.length; i++) {
// Update HTML
$('#gld' + data[i].formNum).html(data[i].cartHTML);
}
}
</script>
Your jsrefreshincart.php should return data for all of this. For example:
<?php
// Used to load the cart data - I'm sure you have something similar
require_once('cart.php');
// Send everything back as JSON
header('Content-type: application/json');
// Initialize the data to send back
$data = array();
// Iterate over all data send to the server
foreach ($_POST['formNums'] as $formNum) {
$data[] = array(
// The unique ID for the form number
'formNum' => $formNum,
// Again, however you get the view data for your cart line items works fine
'cartHTML' => Cart::getCartHTML($formNum)
);
}
// Spit out the JSON data
echo json_encode($data);
Some additional suggestions:
Your variables d, e, and f in your original code are not necessarily all updated during the Ajax round-trip
You need to add more commenting and indentation - it seems simple, but proper documentation is the best way to communicate your problems to other developers
Consider using a different way to keep track of data besides a "count of forms" - classes can work too
My assumption is that anything starting with an ID of ectform is a form to have this functionality captured in; if this is not the case, parts of the above solution might not make sense

After looking at the suggestion by Dykotomee (thank you), it gave me the idea how I could amend my script to work without the loop:
<script>
$(document).ready(function(){ // when DOM is ready
$("[id^=ectform]").on('submit', function(e) { // on submission of any form with id beginning "ectform"
e.preventDefault(); // prevent the form itself submitting the data
var subformid = $(this).attr('id'); // set variable with the id of the submitted form
$(this).ajaxSubmit({ // submit the form via ajax which will add the product to the cart
success:function(){ //on successful submission of the form
$.ajaxSetup({ cache: false }); // turn off cache so the updates will refresh on all browsers
$("#div1").load("jsrefresh.php"); // load div in mini cart with new updated cart quantity
var str = subformid.replace("ectform", ""); // trim subformid to leave just the end digits and call this variable str
var d = "#glc" + str; // not important for purposes of explanation
var f ="#gld" + str; // f is the id of the div in the submitted form to be updated
var e = eval("z" + str); // e is the product number
$(f).html('Adding item to Cart...').load("jsrefreshincart.php",{ prodynum: e, divno: d}); // send data to jsrereshincart.php and load updated html into div f.
}
});
});
});
</script>
I used ajaxSubmit instead of ajaxForm which allowed me to trigger the submission of the form using $("[id^=ectform]").on('submit', function(e) {.......
I was then able to catch the id of the form submitted with var subformid = $(this).attr('id');
Now I had the id of the submitted form , I was able to use ajax .load to get the updated cart HTML into the div in that particular form rather than looping through all the forms and updating them one by one.
The script now only makes a total of 2 server calls per form submission. My previous script made up to 50 calls when a maximum of 25 products/forms were displayed on the products page.
I could modify this script and the php scripts to do everything with a single call but other pages on the site don't have products, just the mini cart so it's easier to keep the scripts separate.

Related

Sending a form through PHP, autosaving with JS every ten minutes

The Environment
PHP: Symfony -> Twig, Bootstrap
Doctrine -> Mongodb
Jquery
The Project
The timer is working, counting the interval, and I can send the form. This is good, but once I get to the part where the form is sent I seem to be running into two problems:
interval counter working
form submitting automatically, then
The null fields do not get accepted
The form does not get validated
The form itself is setup through a custom built PHP graphical interface that allows you to set the simple things very easily: fields, fieldtypes, names and labels, etc.
This is cool, but it means that you can't go in and tinker very much with the form or at all really. The most you can change is aesthetics in the template. Although you could wrap each form element in another form element or some kind of html identifier, this is an option, but a tedious one...
On a valid check the form gets upserted and all is well the else catches the non-valid form and lets the user know that some fields are not filled in. I would post that code here, but I think it would be frowned upon. Hopefully you understand the PHP concept.
The part that I can share is the JS:
autoSaveForm = function() {
var form = $('form'),
inputs = form.find('input');
form.on('submit', function() {
inputs.each( function( input ) {
if (input.attr("disabled") === true){
input.removeAttr("disabled");
}
})
});
function counter(){
var present = $('.minutes').attr('id'),
past = present;
$('.minutes').text(past);
setInterval(function(){
past--;
if(past>=0){
$('.minutes').text(past);
}
if(past==0){
$('.minutes').text(present);
}
},1000);
}
function disableInputs(){
inputs.each( function( input ) {
if (input.val() === ""){
input.attr("disabled", true);
}
});
}
// Start
counter();
// Loop
setInterval(function(){
counter();
form.submit()
},10000);
};
This sets a counter on the page and counts through an interval, it's set to seconds right now for testing, but eventually will be 10 minutes.
Possible Solutions
disable the null fields before submit and remove the attribute after submit is accomplished
this needs to be done so that the user can do a final completed save at the end of the process
this doesn't actaully seem to be disabling the fields
Their were a few things I found about adding in novalidate to the html, but it wasn't supported in all browsers and it might get tricky with the static nature of the forms.
Post the form with ajax and append a save true variable to the end of the url, then redirect it in PHP Controller with a check on the URI var although:
then I still have the null fields
to solve this: set a random value or default value to the fields as they are being passed through. haven't tried this yet
Something kind of like what this question is addressing, although I have some questions still about the null fields - Autosaving Form with Jquery and PHP
Sending the form through ajax
Any input would be greatly appreciated. :) Thanks

Mutiple tag change within Javascript in HTML

this is my json data
[
{
"menu":
{
"MenuID":"1",
"OmfID":"1",
"menu_name":"Coyote Blues Louisiana Menu",
"menu_description":"Full Menu served all day long. ",
"menu_note":null,
"currency_symbol":"$$",
"language":"En",
"disabled":"0",
"menu_uid":"Lake Charles\u0000\u0000\u0000\u0000",
"menu_duration_name":"All Day",
"menu_duration_time_start":"11:00:00",
"menu_duration_time_end":"11:00:00",
"fDateAdded":"2013-12-20 13:00:44"
}
}
]
this is my javascript
function Menus_RestaurantID()
{
var query = $.getJSON('Menus/RestaurantID.json',function(data)
{
console.log("success");
});
query.error(function (data)
{
alert("error");
});
query.complete(function(data)
{
var h=new String();
var text = $.parseJSON(data.responseText);
//alert("data length equals ");
//alert(text.length);
var t=new String();
t+='<ul class="tabs">';
/*for(var i=0;i<text.length;i++)
{
t+='<li>'+text[i]['menu'].menu_name+'</li>';
}
t+='</ul>';
h+='<div class="panes">';*/
for(var i=0;i<text.length;i++)
{
h+='<div>';
//h+=text[i]['menu'].MenuID+'<br>';
//h+=text[i]['menu'].OmfID+'<br>';
//h+=text[i]['menu'].menu_name+'<br>';
if(text[i]['menu'].menu_description!=null)
h+=text[i]['menu'].menu_description+'<br>';
if(text[i]['menu'].menu_note!=null)
h+=text[i]['menu'].menu_note+'<br>';
h+=text[i]['menu'].currency_symbol+'<br>';
h+=text[i]['menu'].language+'<br>';
//if(text[i]['menu'].disabled!=null)
//h+=text[i]['menu'].disabled+'<br>';
h+=text[i]['menu'].menu_uid+'<br>';
h+=text[i]['menu'].menu_duration_name+'<br>';
h+=text[i]['menu'].menu_duration_time_start+'<br>';
h+=text[i]['menu'].menu_duration_time_end+'<br><br><br><br>';
//h+=text[i]['menu'].fDateAdded+'';
h +='</div>';
}
h += '</div>';
//alert("h");
//alert(h);
$('#menus').append(t);
$('#menus').append(h);
});
$(function()
{
// setup ul.tabs to work as tabs for each div directly under div.panes
$("ul.tabs").tabs("div.panes > div");
});
I'm retrieving the data right but I want to display the information in tab dividers. Like in http://jquerytools.org/demos/tabs/index.htm but as of right now the only thing it does is shows all the data in just one. I'm not sure if its because of how im retrieving the data or what.
My Question is:
Why isn't my code displaying properly?
What is another way to display the data in tabs?
The following line sets up the tabs:
$("ul.tabs").tabs("div.panes > div");
However, that is run when the page loads. At that point your tabs do not exist in the page. You add them later via the ajax request. You need to add that line to the complete callback after you have added the tabs to the page.
Edit:
Bunch of problems here
Your tabs ulis empty since the code that fills it is commented out
You have no connection between the list items (which I guess are meant for the tab header) and the divs containing the tab content (the divs should have an id and the links in the list items should target that id)
You need to call .tabs() on the container containing both the headings and the content, not just the headings
You should be calling .done() not .complete()
You had called $.getJSON so the data returned will be parsed JSON already but you try to parse it again.
I think you might want something like this fiddle. (I have changed to hard-code the var data in the .done() to make it work in the fiddle. In a real use case remove the var data = ... defintion and set data as a paramater to the callback like query.done(function(data){ )
I suggest also re-reading the tabs documentation and using a debugger to see what is sent back and forth when you make ajax requests and what error messages come in the console (my personal preference is for Firebug but Chrome dev tools and fiddler are also options)

Sending form variable data to another website on form submission

We have clients that we want to collect some of their form submission data for. A user will fill out a form on their site and when the form is submitted, the following javascript is called:
/* 4. Below script will get all field name/value pairs for given form */
function cpcshowElements(f) {
var formElements = "";
for (var n=0; n < f.elements.length; n++) {
box = f.elements[n];
if (!f.elements[n].value == ""){
formElements += box.name + ":" + f.elements[n].value + ",\n";
}
}
var track = new Image();
/*send data to us*/
track.src="https://www.xxx.com/form_record.cfm?form="+formElements;
//alert("The elements in the form '" + f.name + "' are:\n\n" + formElements);
}
This calls code on our end that should grab the data sent and save it. This works great, but doesn't work all of the time. When testing, we seem to not get the data consistently. I haven't been able to figure out why this works sometimes and not others. I'm not a javascript expert so I'm not sure if it's just the way javascript works. The only thing I've been able to think might be the issue is that once the clients website finishes processing the form on their end and the user is directed to another page, the script will stop running if it hasn't already finished and so we won't get the data. Anyone have any ideas? Am I on the right track here? Any ideas on how to make it so we will get the data every time?
You could you jQuery Framework with serialize function tosubmit the form and get it input's values.
$("#bottonId").click(function(){
imageObj.src ="http://www.mypage.com/mypage?" +$("#form's ID").serialize();
});

Go back to previous page from JS function and retain the field values

I want to go back to previous JSP page with all its value retained on click of previous button in present JSP page. I am using history.back() in JS, but not able to retain the previous field value. How to retain the field values of the previous page?
I would suggest using JQuery and a server side session variable to store the values.
make sure you have an html id on each form element you need to keep
on unload, loop though the elements and send them over to the server to be saved
$(window).unload(function() {
var formValues = {}
//get the form elements
elements.each(function() {
var fieldID = $(this).attr("id");
formValues[fieldID] = $(this).val();
}
json_form = JSON.stringify(formValues);
$.post("/save_form_values/", {form : json_form} );
I haven't included any code for storing on the server (I found it pretty straightforward with django / python).
make another ajax call when you reload the page
$(document).ready(function() {
$.get("/get_form_values/", function(data) {
var formValues = JSON.parse(data);
$.each(formValues, function(fieldID, value) {
id_selector = '#' + fieldID;
$(id_selector).val(value);
}
}
}

How to continue running execution after form submit?

I am writing a simple form submit function for a specific site.
The script fills the specific form on the current page and submits the form. It MUST also fill the second form which appears after the first form is submitted and submit this form too.
That is there are 2 forms that must be filled and submitted.
Problem however, is that on a normal page the script fills and 1st form and submits it. After submission however, the script stops working! I want to continue execution!
I've done it by mistake on a page that had 2 frames! most pages don't have frames!
function FillFirstForm(){
doc=document;
//Some code removed from above...Fill Values
doc.forms[0].name.value = answerarray[1];
doc.forms[0].address.value = answerarray[2];
doc.forms[0].phone.value = answerarray[3];
doc.forms[0].username.value = answerarray[4];
//And Press Button
doc.forms[0].submit.click();
iTimer=setInterval(FillSecondForm,5000);
return true;
}
function FillSecondForm(){
clearInterval(iTimer);
doc.forms[0].tags.value = answerarray[5];
doc.forms[0].reference.value = answerarray[6];
document.forms[0].submit.click();
return true;
}
The basic rule is that a classical form submission halts all execution of scripts of the page, and loads the next page. No way to do anything about that.
You may have to switch to sending your form's contents using Ajax. That will leave the current page alive, and allow you to do as many submits as you want to.
A very easy way to achieve this is the jQuery form plugin. It takes much of the manual hassle out of the process.
Can you call FillSecondForm() function on body load of second form, once first form submitted.
You could POST the first form with AJAX, and then submit the second form after receving the response for the first form.
Something like this perhaps:
function FillFirstForm() {
var post_data = 'name='+escape(answerarray[1]);
post_data += '&address='+escape(answerarray[2]);
post_data += '&phone='+escape(answerarray[3]);
post_data += '&username='+escape(answerarray[4]);
// TODO: make this cross browser :)
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if ( req.readyState == 4 ) { // The request has finished
if ( req.status == 200 ) {
FillSecondForm();
}
else {
// Deal with errors here
}
}
};
req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
req.open('POST', '/submit_url', true);
req.send(post_data);
}
W3 schools has a tutorial on AJAX here: http://www.w3schools.com/ajax/ajax_xmlhttprequest_create.asp, and there are many more on the web.

Categories

Resources