Too many ajax calls when form selections change - javascript

My webpage has two main sections: (1) search criteria (selection boxes in a form) used to access database information, and (2) a div in which the results are displayed. When the page loads initially, default values in the form are serialized and sent via ajax to php and the results are rendered. This results section is paginated to display all the results by clicking next, previous, etc. This all works perfectly.
Here’s the problem: each time the user makes a change to the criteria and the form’s data is serialized and sent via ajax, another layer of results is added somehow. When paginating through the results, it processes page 2 for each of the “layers” but only the last one that arrives from the server is displayed on the webpage. So, every time another change is made, another layer is added. Since ajax is asynchronous, the results displayed may or may not be the correct “layer.”
HTML:
<form id='submitCriteria' action='' method='post'>
<select id='selLevel' class='selectpicker' name='levels'>
<option title='Levels' value='No Preference'
selected = 'selected'>No Preference</option>
<option title='Levels:<br> 1+' value=1 >1+ </option>
<option title='Levels:<br> 2+' value=2 >2+ </option>
<option title='Levels:<br> 3+' value=3 >3+ </option>
</select>
</form>
<!-- Pagination: -->
<div id="spinnerDet" class="spinnerA">
</div>
<div id="paginationdiv">
<div id="pagination_container">
<div class="pagination">
<ul><li class="inactive">Previous</li>
<li class="pagerange">
<span class="total" a=" 58">
Page 1 of 58 </span></li>
<li p="2" class="active">Next</li>
</ul>
</div>
<!-- Output from server: -->
<table>
<tr><td>Levels</td><td>3</td></tr>
</table>
</div>
</div>
javascript/jQuery:
$("#submitCriteria").change(function(e) {
e.preventDefault();
e.stopPropagation();
$.ajax({
type: 'post',
data: $("#submitCriteria").serialize(),
url: "/load_plans.php",
success: function(data) {
paginateDetails (data)
},
});
return false;
});
function paginateDetails (data) {
selDetails = JSON.parse(data);
var levels = selDetails.levels;
var totalsline = "Number of levels: " + levels;
$('#numResults').removeClass('spinnerA');
$('#numResults').addClass('stop-spin');
$('#numResults').html(totalsline);
loadData(1); //initial output based on default values
// Pagination buttons event:
$('#paginationdiv').on('click touchend',
'#pagination_container .pagination li.active', function (e) {
e.stopPropagation();
e.preventDefault();
var page = $(this).attr('p');
loadData(page);
});
function loadData(page) {
$.ajax({
type: "POST",
data: eval("'page=' + page + '&levels=' + levels"),
url: "loadDetails.php",
success: function (msg) {
$("#pagination_container").ajaxComplete(function (event, request, settings) {
$("#pagination_container").html(msg);
});
}
});
}
}
How do I eliminate another “layer” when selections in the form are changed/updated?

I think the problem is with the structure of your code, in this case you shouldn't be nesting the functions. Also you are repeatedly attaching click event to #paginationdiv (does it get removed and reatached when you reload data? You should use class instead of div in that case).
Without trying the code, i believe your problem might be caused by your loadData function - in your success callback you don't need to hook ajax complete again, success is called when your request is complete and successfull. I believe that part of your code was triggering twice ( on success and when ajaxComplete fired)
Your refactored code should look something like this:
$("#submitCriteria").change(function(e) {
e.preventDefault();
e.stopPropagation();
$.ajax({
type: 'post',
data: $("#submitCriteria").serialize(),
url: "/load_plans.php",
success: function(data) {
paginateDetails (data)
},
});
return false;
});
function loadData(page) {
$.ajax({
type: "POST",
data: eval("'page=' + page + '&levels=' + levels"),
url: "loadDetails.php",
success: function (msg) {
//$("#pagination_container").ajaxComplete(function (event, request, settings) {
$("#pagination_container").html(msg);
//});
}
});
}
function paginateDetails (data) {
selDetails = JSON.parse(data);
var levels = selDetails.levels;
var totalsline = "Number of levels: " + levels;
$('#numResults').removeClass('spinnerA');
$('#numResults').addClass('stop-spin');
$('#numResults').html(totalsline);
loadData(1); //initial output based on default values
// remove previous click handlers
$('#paginationdiv').off()
// Pagination buttons event:
$('#paginationdiv').on('click touchend',
'#pagination_container .pagination li.active', function (e) {
e.stopPropagation();
e.preventDefault();
var page = $(this).attr('p');
loadData(page);
});
}

Related

JS Create delay on Select Drop-Down Menu Open

I have a drop-down menu that lists subjects. I am loading those subjects via an AJAX call. The subjects load properly, they just don't load fast enough to populate the select menu until AFTER the menu has been opened. This causes the user to need to open the menu, close the menu, then open it again.
How can I cause a delay on the drop-down-menu open to give the response enough time to populate the drop-down menu? Thanks for any and all help.
Code:
Drop-down Menu
<div id="subjectForm" class="form-row">
<label>1) Subject Selection:</label>
<select name="subject" id="subjectSelect" class="input-medium">
<option value="0">All</option>
</select>
</div>
AJAX Call
document.getElementById("subjectForm").addEventListener("click", function( event ) {
var selectCount = $('#subjectSelect option').size();
if(selectCount == 1) {
$.ajax({
url: '/v2/subjects?',
method: 'GET',
data: {'core': number},
success: function (data) {
// Populates the $subjectSelect filter with subjects
// For each grade brought back from response, add it to the grade filter
$.each(data, function(i, subject){
$('#subjectSelect')
.append($('<option></option>')
.attr("value", subject.id)
.text(subject.title));
});// each
}// success
});// ajax
}// end if
}, false);// #subjectForm clicked
Since the number value is defaulted, I would change the load to happen on document ready, rather than waiting until the click event.
$(document).ready(function () {
var loadSubjectSelect = function(){
var selectCount = $('#subjectSelect option').size();
if(selectCount == 1) {
$.ajax({
url: '/v2/subjects?',
method: 'GET',
data: {'core': number},
success: function (data) {
// Populates the $subjectSelect filter with subjects
// For each grade brought back from response, add it to the grade filter
$.each(data, function(i, subject){
$('#subjectSelect')
.append($('<option></option>')
.attr("value", subject.id)
.text(subject.title));
});
}
});
}
};
loadSubjectSelect();
})();
Then when you add the other menu, you can call loadSubjectSelect() on its click event.
Render options after some seconds
success: function (data) {
// Populates the $subjectSelect filter with subjects
// For each grade brought back from response, add it to the grade filter
var myoptions = "";
$.each(data, function(i, subject){
myoptions += "<option value='"+subject.id+"'>"+subject.title+"</option>";
});
$('#subjectSelect').html(myoptions);
}
Hope it solves the problem.

javascript ajax and post value is working all together why

I am having a some problem in my java script and to get the request.
This is the HTML
<form method="post" id="searchform">
<div align="center" class="col-md-10">
<input type="text" id= "contentSearch" name="contentSearch" >
</div>
<div class="form-group"><button type="submit" class="btn btn-default" id="submitSearch">
<i class="fa fa-search"></i> Search
</button></div>
</form>
<----Scenario 1 ---->
This script works fine and post the value and as ajax it never reload the page
<script>
$(document).ready(function () {
$("#submitSearch").on('click', function (e) {
e.preventDefault();
e.stopPropagation();
var data = {};
data['contentSearch'] = $('#contentSearch').val();
// Submit data via AJAX§
$.ajax({
url: '/home',
type: 'post',
data: data,
success: function (data) {
// do i need to do something here !!
}
});
});
});
</script>
When i check the POST value i can see the value is been POST.
The Problem is when i try to get the request data from controller like ---
$post_value = $request->request->get('contentSearch');
print_r($post_value);
OUTPUT : empty
<----Scenario 2 ---->
This script have a problem i think, because it reload the page for returning the result and displaying the value ---
<script>
$(document).ready(function () {
$("#searchform").on('submit', function (e) {
e.preventDefault();
var data = {};
data['contentSearch'] = $('#contentSearch').val();
$.ajax({
url: '/home',
type: 'post',
data: data,
success: function (data) {
}),
return false;
});
});
</script>
than i am able to get the post value like so--
$post_value = $request->request->get('contentSearch');
But the problem is in the second script the page is always loading when return the request which is not a ajax behave.
And in the first script i think because of the **e.preventDefault();** i am not getting the POST value in my controller.
Expected result ---
Option 1 : Do something so i can get the POST value in my controller
Option 2 : Fix this script so the page do not load to return the result and display
I am working on symfony framework .
Can someone please help me to fix this problem, i am really getting sick of to solve this problem.
Thanks a lot on advanced.
Like I mentioned in the comments, you need to be targeting the submit on the form. Not a click event. When targeting the click you are firing both the click and submit events, hence the reload.
$(document).ready(function () {
$("#searchform").on('submit', function (e) {
var data = {};
data['contentSearch'] = $('#contentSearch').val();
$.ajax({
url: '/home',
type: 'post',
data: data,
success: function (data) {
}
});
return false;
});
});

How to call ajax again when user click back button to go back last webpage?

Below is my code..
HTML Code
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="body">
<div class="dropdown_div">
<select id="q_type" class="dropdown" onchange="getSubject(this.value)">
<option>Question1</option>
<option>Question2</option>
</select>
</div>
<div class="dropdown_div">
<select id="q_subject" class="dropdown">
<option>Subject1</option>
</select>
</div>
</div>
JS Code
function getSubject(val){
$("option", $("#q_subject")).remove();
var option = "<option>Subject</option>";
$("#q_subject").append(option);
$.ajax({
url: "api.path",
type: 'POST',
dataType: 'json',
data: {id: id},
async: true,
cache: false,
success: function(response) {
alert("Hi");
$("option", $("#q_subject")).remove();
var option = "<option>Subject1</option>";
option += "<option value=1234>Subject2</option>";
$("#q_subject").append(option);
}
});
}
How do I use pushState into my code and let user can click back button to return last page and then still see the ajax data?
First of all, you should save data received from ajax request to browser local storage. Afterwards, in order to show ajax result when browser "back" button was fired, you should bind statements that you are calling in ajax.success() method to window onpopstate event. To omit code duplication, it`s better to use a declared function instead of anonymous one.
function success(response) {
alert("Hi");
$("option", $("#q_subject")).remove();
var option = "<option>Subject1</option>";
option += "<option value=1234>Subject2</option>";
$("#q_subject").append(option);
}
Save data to localstorage and call success function:
$.ajax({
url: "api.path",
type: 'POST',
dataType: 'json',
data: {id: id},
async: true,
cache: false,
success: function(response) {
localStorage.setItem("response", response);
success(response);
}
});
Call success() when "back" button was fired:
window.onpopstate = function (e) {
var res = localStorage.getItem('response');
success(res);
}
I would rather suggest you to use sessionStorage which expires when the browser window is closed :)
$.ajax({
url: "api.path",
type: 'POST',
dataType: 'json',
data: {id: id},
async: true,
cache: false,
success: function(response) {
sessionStorage.setItem("DataSaved", response);
success(response);
}
});
And then
window.onpopstate = function (e) {
var res = sessionStorage.getItem('DataSaved');
success(res);
}
You can solve this using the local Storage or Session storage. You will also need to have a onload function callback, to check if there are any previous values that you stored in the local/session storage, if yes, then show that data in the select box.
I noticed this Back() issue when using Ajax to navigate an MVC-5 application from within a JavaScript generated diagram. All clicks in the diagram are handled by Ajax.
Above solutions do not replace the complete body, in the repaired cases a Back() would restore just the edit fields. In my case, I don't need that. I need to replace the entire page from the AJAX and also enable the Back button to return to my original diagram context.
I tried above solution to replace body, and I have to note, it would only trigger the window.pop event after
history.pushState({}, '')
But when the event triggered and it uses Ajax to fill the body, my Javascript would not properly re-initialize the diagram page.
I decided to use another pattern, to circumvent the the window.pop event and avoid the back-issue. Below code will not return into the Ajax code context, but instead simply replace current page, processing the Ajax return information from the server (=Controller) as a redirect link, like
var url = "/ProcessDiagram/MenuClick?command=" + idmenuparent+"_"+citem; // my Ajax
$.get(url,
function (data) {
window.location = data; // Server returns a link, go for it !
return true; // Just return true after going to the link
});
.. this will preserve the Back() context, because the browser will take care of things.
Controller side composes the redirect link, like
public ActionResult MenuClick(string command)
{
List<string> sl = command.Split(new char[] {'_'}).ToList();
var prId = int.Parse(sl[0].Substring(3));
if (sl[1] == "PU")
return Content("/ProductionUnitTypes/Details/" + UnitContextId(prId) );
if (sl[1] == "IR")
return Content("/ItemRoles/Details/" + RoleContextId(prId) );
// etcetera
}
I solved it by including the below code just before the $.get() function
$.ajaxSetup({cache: false});
It works! Try it :)

Bootstrap popover repeats an action/ event twice?

Why Bootstrap's popover repeats an action twice? For instance, I want to submit a form inside the popover's data-content via ajax. It repeats all the form data twice and the posts form twice.
Any idea what I can do about it?
jquery + bootstrap,
$('.bootstrap-popover-method').popover({
placement: 'bottom',
container: 'body',
html:true,
content: function () {
var p = $(this);
var data = $('#popover-content').html();
$('#popover-content').remove();
p.attr("data-content", data);
p.popover('show');
}
});
$('.bootstrap-popover-method').on('shown.bs.popover', function () {
// do something…
console.log(this); // I get twice of the button element <button class="btn btn-default bootstrap-popover-method"...>
console.log($(".btn-submit").length); // I get twice of '1'.
$(".link").click(function(){
console.log($(this).attr("href")); // I get once of 'test.html'.
return false;
});
$(".btn-submit").click(function(){
console.log($(this).closest("form").attr("action")); // I get twice of '1.php'
var form = $(this).closest("form");
console.log(form.serialize()); // I get twice of 'username=hello+world!'
$.ajax({ // it posts twice to 'POST https://localhost/test/2014/css/bootstrap/1.php'
type: "POST",
url: form.attr("action"),
data: $(this).serialize(), // serializes the form's elements.
success: function(data){
//alert(data); // show response from the php script.
}
});
return false;
});
});
bootsrap + html,
<button type="button" class="btn btn-default bootstrap-popover-method" data-title="body" data-container="body" data-toggle="popover" data-placement="bottom">
Popover on bottom
</button>
<div id="popover-content">
hello
<form action="1.php" class="myform">
<input type="text" name="username" value="hello world!"/>
<input type="submit" value="submit" class="btn-submit"/>
</form>
</div>
This happens because popover.content checks if the tooltip is empty or not.
A simple fix would be to add a title attribute to popover.
$('.bootstrap-popover-method').popover({
placement: 'bottom',
container: 'body',
html:true,
title: "New Title",
content: function () {
var p = $(this);
var data = $('#popover-content').html();
$('#popover-content').remove();
p.attr("data-content", data);
p.popover('show');
}
});
https://github.com/twbs/bootstrap/issues/12563#issuecomment-56813015
This might be an old post, but i'm gonna leave here my work around.
I'm using bootstrap 3.3.5.
So the buggy behavior is that on every execution of "popover('show')", Bootstrap calls the rendering function twice, and only the second call is the one that actually renders the popup.
My fix is to return a short html string for the first call, and for the second call i let run the whole rendering function:
jQuery('.bootstrap-popover-method').popover({
html: true,
trigger: 'manual',
content: function(){//This is our rendering function for the popup's content
var __G_bs_popover_shown= jQuery.data(jQuery('body')[0], '__G_bs_popover_shown');
//Create a global variable, attached to the body element, to keep track of the repeating calls.
__G_bs_popover_shown= (typeof __G_bs_popover_shown == 'undefined') ? 1 : (__G_bs_popover_shown + 1) % 2;
//Update the global var
jQuery.data(jQuery('body')[0], '__G_bs_popover_shown', __G_bs_popover_shown);
//return a short string on every first call (this will not be rendered, anyway)
if(__G_bs_popover_shown == 1) return '<div>BLANK</div>';//==>this should not be an empty string!
//PLACE YOUR CODE HERE, E.G. AJAX CALLS, ETC..
//DON'T FORGET TO RETURN THE HTML FOR THE POPUP'S CONTENT!
}
});
I think you need to prevent the default event of the submit button
$(".btn-submit").click(function(e){
e.preventDefault();
console.log($(this).closest("form").attr("action")); // I get twice of '1.php'
var form = $(this).closest("form");
console.log(form.serialize()); // I get twice of 'username=hello+world!'
$.ajax({ // it posts twice to 'POST https://localhost/test/2014/css/bootstrap/1.php'
type: "POST",
url: form.attr("action"),
data: $(this).serialize(), // serializes the form's elements.
success: function(data){
//alert(data); // show response from the php script.
}
});
return false;
});
$('.bootstrap-popover-method').off('shown.bs.popover')
.on('shown.bs.popover', function (e) {
e.preventDefault();
}
// unbind your submit button click
$(".btn-submit").off('click').on('click',function(){
console.log($(this).closest("form").attr("action")); // I get twice of '1.php'
var form = $(this).closest("form");
console.log(form.serialize()); // I get twice of 'username=hello+world!'
$.ajax({ // it posts twice to 'POST https://localhost/test/2014/css/bootstrap/1.php'
type: "POST",
url: form.attr("action"),
data: $(this).serialize(), // serializes the form's elements.
success: function(data){
//alert(data); // show response from the php script.
}
});
return false;
});

jquery ajax calls conflict?

On my site i am loading shopping products with the "add to cart"-button dynamically with a jquery ajax call. For the shopping cart itself, I use jcart, jquery plugin.
When I then add an item to the cart, jcart calls a php-file with ajax and POST. All works fine, the products are correctly added to the cart, but the page reloads every time I add an item to the cart.
When I don't use the ajax call to load the products (e.g. load them directly in the page), all works fine, so there must be a conflict somewhere.
Any clues?
This is my products-function and the html.
...
<script>
function loadProducts(str) {
$.ajax({
type: 'GET',
async: true,
url: 'ajax/load.php',
data: {'max-id' : str},
cache: false,
success: function(response) {
$('#products').html(response).fadeIn('slow');
},
});
}
</script>
<script>
$(document).ready(function() {
var n = '';
loadProducts(n);
});
</script>
<script src="jcart/js/jcart.js"></script>
</body>
</html>
The jcart-Plugin with its ajax-call can befound here:
http://conceptlogic.com/jcart/standalone-demo/jcart/js/jcart.js
Here are the functions from jcart.js.
$.ajaxSetup({
type: 'POST',
url: path + '/relay.php',
cache: false,
success: function(response) {
// Refresh the cart display after a successful Ajax request
container.html(response);
$('#jcart-buttons').remove();
},
error: function(x, e) {
...
}
});
...
function add(form) {
// Input values for use in Ajax post
var itemQty = form.find('[name=' + config.item.qty + ']'),
itemAdd = form.find('[name=' + config.item.add + ']');
// Add the item and refresh cart display
$.ajax({
data: form.serialize() + '&' + config.item.add + '=' + itemAdd.val(),
success: function(response) {
// Momentarily display tooltip over the add-to-cart button
if (itemQty.val() > 0 && tip.css('display') === 'none') {
tip.fadeIn('100').delay('400').fadeOut('100');
}
container.html(response);
$('#jcart-buttons').remove();
}
});
}
...
// Add an item to the cart
// is called from the submit-buttons within each product picture
$('.jcart').submit(function(e) {
add($(this));
e.preventDefault();
});
The "loadProducts()" function puts this into #products container for each item:
<form method="post" action="" class="jcart">
<fieldset>
<input type="hidden" name="jcartToken" value="<?php echo $_SESSION['jcartToken'];?>" />
<input type="hidden" name="my-item-id" value="SDK12345" />
<input type="hidden" name="my-item-name" value="Product Name" />
<input type="hidden" name="my-item-price" value="1.00" />
<input type="hidden" name="my-item-qty" value="1" />
<ul>
<li><img src="product-image.jpg"/></li>
<li>1.00 Dollar</li>
</ul>
<input type="submit" name="my-add-button" value="Add to cart" class="button" />
</fieldset>
</form>
I'm guessing you are calling the loadProducts() function in a binded click action on your add to cart button. If you are using an element with a default click behavior. You might want to prevent that with a 'return false;' on the last line of your binded click function.
like this:
$('a.addtocart').bind('click', function(){
//logic here (ajax)
return false;
});
After your success function there's also a comma that might get messy in IE:
success: function(response) {
$('#products').html(response).fadeIn('slow');
},
Remove the comma
I think there's an error in your ajax call, try to work it out... i cant see the logic of your php file that adds products to your basket. but if you want to send the data of your form (quantity, itemid), serializing your form data should be enough. No need to pass extra get variables.
function add(form) {
$.ajax({
data: form.serializeArray(),
url: 'yourfile.php',
success: function(response) {
// logic
}
});
}
Ok, I found the solution.
As the forms are loaded via ajax, they were no correctly interpreted by jcart.js (though the functions all worked fine for themselves).
"bind" didn't work, but "live" fixed it:
$('.jcart').live('submit',function(e) {
add($(this));
e.preventDefault();
});

Categories

Resources