Fire Jquery ajax only once, if already fired - javascript

I am facing some problems with my Ajax calls.
I am working to improve my site's performance, and for that 1 thing I want to do is fire ajax only once, if they have been fired before, not to fire them.
One of My Scenario.
I have 2 select drop downs - Country and zones.
when a country is changed, .change is fired which fires an ajax to get the zones of the selected country.
Now, for eg, If I select country India, Ajax is fired, and change it to Iceland, ajax is fired.
Now if i change my country back to india, Ajax should not be fired, as I have already fetched data from server.
CODE
$("#select_list_id").change(function(){
var url = 'ajax.php?val=' + this.value;
$.ajax({
url: url,
success: function(json){
for(i=0; i<jsonData.length;i++) {
$("#select_list_2_id").append(new Option(jsonData[i].title,jsonData[i].id));
}
}
});
})
My Approach can be to store the json being returned, and compare the countryID on change, if the value already exists, return the json back, else hit the Ajax.
But I have near about 100 ajax calls in my project, and this process might take some sweet time.
If anyone can help me, in how to generalize this code.
Apart from all this, while searching I found that this can be done via jquery once plugin as well, if so, can someone please provide some help on this.
Updated -
Thanks everyone, this did help me, and things are pretty good now :)
Just another small query, what is the use of jquery once plugin then ? Is it used for same stuff ?

if you can generalize your ajax calls, you could cache the result json by the request uri (url+params)
something like this:
var ajaxCache = [];
function ajaxCall(url,successFunc)
{
if(ajaxCache[url] != undefined)
{
successFunc(ajaxCache[url]);
}
else
{
$.ajax({
url: url,
success: function(json){
ajaxCache[url] = json;
successFunc(json);
}
});
}
}
$("#select_list_id").change(function(){
ajaxCall('ajax.php?val=' + this.value, function(json){
for(i=0; i<jsonData.length;i++) {
$("#select_list_2_id").append(new Option(jsonData[i].title,jsonData[i].id));
}
});
});

You can store the response on the option that has emitted that request:
$("#select_list_id").change(function() {
var $selected = $(this).children(":selected");
if ( $selected.data("json") ) {
build( $selected.data("json") );
}
else {
$.ajax({
url: 'ajax.php?val=' + this.value,
success: function(json) {
$selected.data("json", json);
build(json);
}
});
}
function build(jsonData) {
for(i=0; i<jsonData.length;i++) {
$("#select_list_2_id").append(new Option(jsonData[i].title,jsonData[i].id));
}
}
});

Assuming that the request is not cached, this is still relatively simple. You would maintain an object with country names as the keys and options as the values:
var countries = {};
.change(...
var country = this.value;
if (!countries.hasOwnProperty(country)) {
countries[country] = [];
$.ajax ...
for (var i = 0; ...
countries[country].push(new Option(...
}
//Iteration may be needed
$("#select_list_2_id").empty().append(countries[country]);

Related

AJAX call not firing from inside if statement

I have the following code. There is a button in the UI that when clicked executes the if statement. I pass in a URL from a database and compare it to the current URL the user is on. If they match I want to run the code below, else I want to open the correct tab then run the code below.
With this code below I mean everything below starting from $('#sceanrioDropdownList').change(function () {...}. The code then checks a drop down and gets the selected Id from which an AJAX call is made to my web API that uses that Id in a stored procedure to return the results. The returned data is then iterated over and stored in variables which I am using to append to specific inputs, buttons and drop downs.
This is what I have so far and I think I have developed this correctly. The issue that I am currently having is that the UI wants everything from ... to be run if the if statement is true. I have tried CTRL+C and CTRL+V to copy the code into the if statement. I have also tried putting it in a new function and referencing that function n the if statement. Both do not work and I was using console.log to inspect the returned data.
It does however when I attempt to call it from inside i statement it doesn't return any data or error. It just doesn't seem to fire.
Is there a way in which I can achieve the functionality I desire? Do you have any suggestions as to if I have done something wrong. Thanks in advance.
$('#automate').click(automateButton);
function automateButton() {
if (webpageUrl == activeTabUrl) {
// do nothing
} else {
// Window opens
window.open(webpageUrl);
}
}
$('#scenarioDropdownList').change(function() {
var scenarioId = $('#scenarioDropdownList option:selected').prop('id');
getData(scenarioId);
});
function getData(scenarioId) {
$.ajax({
type: "GET",
url: 'http://localhost:54442/api/scenariodatas/GetScenarioData',
data: {
scenarioId: scenarioId
},
dataType: 'JSON',
success: scenarioData,
error: function() {
console.log("There has been an error retrieving the data");
}
});
}
function scenarioData(response) {
$.each(response, function(key, val) {
var fieldType = val.fieldType;
var fieldName = val.fieldName;
var fieldValue = val.fieldValue;
var field = $(fieldName);
if (field != undefined) {
switch (fieldType) {
case "Input":
$(field).val(fieldValue);
break;
case "Button":
$(field).click();
break;
case "Select":
$(field).val(fieldValue);
break;
}
}
})
}
onChange don´t work well with buttons because onChange detect a change in the value of your component, because of this, it´s highly recommended to use onClick when you use a button.
$('#scenarioDropdownList').click(function() {
var scenarioId = $('#scenarioDropdownList option:selected').prop('id');
getData(scenarioId);
});
I recommend you to put alerts when you are trying to test this sort of JS
EJM:
$('#scenarioDropdownList').change(function() {
alert('button active');
var scenarioId = $('#scenarioDropdownList option:selected').prop('id');
getData(scenarioId);
});
this alert allow you to know if the code is firing or not

Jquery scroll is not picking changed variable value to be sent to ajax

I am not a regular programmer and has learnt whatever programming I know by google or by asking things here from Stackoverflow.
I am trying to create a ajax function which will fetch feeds from database on scrolling based on selected parameter. User can select either to select public feeds or personal feeds. His chosen value is updated in hidden text field. Code follows as below.
//feed menu switch between personal and public
$('.menu_selection').iCheck({
checkboxClass: 'icheckbox_square',
radioClass: 'iradio_square-blue',
increaseArea: '20%' // optional
});
$("body").on("ifChecked",".menu_selection",function(){
var feed_menu_selected = $(this).val();
$("#feed_menu_selected").val(feed_menu_selected);
$("#member_menu_area").html(loader);
IndexFeederLoader('0','0','0');
});
Now this is function which is fetching records where group_no is the record set being fetched, total_m_group is total number of records, feed_menu_selected is the choice between public or private.
function IndexFeederLoader(group_no,total_m_group,movie_shown){
var feed_menu_selected = $("#feed_menu_selected").val();
$.ajax({
url: '../index-feeds.php',
type: "POST",
dataType:"text",
data: 'feed_menu_selected='+feed_menu_selected+'&group_no='+group_no+'&movie_shown='+movie_shown,
cache: false,
async: false,
success: function(data){
if(group_no == 0)
{
$("#member_menu_area").html(data);
//when personal is checked and not signed in
var notsigned = $(data).filter('#notsigned').text();
if( notsigned !== '')
{
$("#SignInForPersonal").show();
}
}
else
{
$("#member_menu_area").append(data);
}
total_m_group = $("#total_page_no").text();
$("#total_m_group").remove(); // removing extra
movie_shown = $("#movie_shown").text();
$("#movie_shown").remove(); // removing extra
},
complete: function(){
$(window).on("scroll",function(){
var closeToBottom = ($(window).scrollTop() + $(window).height() > $(document).height() - 500);
var AtBottom = ($(window).scrollTop() + $(window).height() == $(document).height());
if (closeToBottom || AtBottom)
{
if( total_m_group != 0 )
{
if( group_no < total_m_group )
{
group_no++;
IndexFeederLoader(group_no,total_m_group,movie_shown); // group_no is not changing
}
}
else
{
group_no = 0;
}
}
});
},
error:function (xhr, ajaxOptions, thrownError){
alert(thrownError);
}
});
}
Now the problem. If I do not switch between public and personal, everything goes well and I get records in order of group_no set. But when I select personal and then come back to private, it does not work giving feeds from start but from where it has left. It seems like group_nois not changing.
Thanks for reading. It would be great if anyone can help me pls.
First problem i can see - in your $.ajax in complete callback you attach new event on $(window) each time it's executed. So when you execute 2 times it'll be 2 events called and so on. Change logic to attaching event once and changing context of it if it's needed.
Second - don't mix up variable types. You're executing IndexFeederLoader passing Strings, but using Numbers
JsFiddle to understand what's happening
So, like you're doing - i'm attaching an event over and over again, passing context variable. Try pressing button - it will fire a lot of different events with it's own context eventually. That is what probably causing bugs in your code.

Creating ajax request loop within an 'each' function

This topic is covered in a few other questions, but I had some difficulty applying the suggested approaches into this use case. I have a checkbox list, where a user can select n sub-sites to publish their post to. since this list could grow to be 100+, I need an efficient way to perform an expensive task on each one. It's okay if it takes awhile, as long as Im providing visual feedback, so I planned to apply an "in progress" style to each checkbox item as its working, then move to the next item int he list once it is successfully published. Also note: I'm working in the WordPress wp_ajax_ hook but the PHP side of things is working well, this is focused on the JS solution.
This code is working right now (console.logs left in for debug), but I've seen multiple warnings against using async: true. How can I achieve a waterfall AJAX loop in a more efficient way?
//Starts when user clicks a button
$("a#as_network_syndicate").click( function(e) {
e.preventDefault(); //stop the button from loading the page
//Get the checklist values that are checked (option value = site_id)
$('.as-network-list').first().find('input[type="checkbox"]').each(function(){
if($(this).is(':checked')){
blog_id = $(this).val();
console.log(blog_id+' started');
$(this).parent().addClass('synd-in-progress'); //add visual feedback of 'in-progress'
var process = as_process_syndication_to_blog(blog_id);
console.log('finished'+blog_id);
$(this).parent().removeClass('synd-in-progress');
}
});
});
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
var result = as_syndicate_to_blog(data);
console.log('end 2nd func');
return true;
}
function as_syndicate_to_blog(data){
$.ajax({
type : "post",
dataType : "json",
async: false,
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id},
success: function(response) {
if(response.type == "success") {
console.log(response);
return response;
} else {
}
},
error: {
}
});
}
Indeed, doing synchronous AJAX request is bad because it will block the browser during the whole AJAX call. This means that the user cannot interact with your page during this time. In your case, if you're doing like 30 AJAX calls which take say 0.5 seconds, the browser will be blocked during 15 whole seconds, that's a lot.
In any case, you could do something following this pattern:
// some huge list
var allOptions = [];
function doIntensiveWork (option, callback) {
// do what ever you want
// then call 'callback' when work is done
callback();
}
function processNextOption () {
if (allOptions.length === 0)
{
// list is empty, so you're done
return;
}
// get the next item
var option = allOptions.shift();
// process this item, and call "processNextOption" when done
doIntensiveWork(option, processNextOption);
// if "doIntensiveWork" is asynchronous (using AJAX for example)
// the code above might be OK.
// but if "doIntensiveWork" is synchronous,
// you should let the browser breath a bit, like this:
doIntensiveWork(option, function () {
setTimeout(processNextOption, 0);
});
}
processNextOption();
Notice: as said by Karl-André Gagnon, you should avoid doing many AJAX requests using this technique. Try combining them if you can, it will be better and faster.
If you can't pass the whole block to the server to be processed in bulk, you could use a jQuery queue. This is using your sample code as a base:
var $container = $('.as-network-list').first();
$container.find('input[type="checkbox"]:checked').each(function(){
var $input = $(this);
$container.queue('publish', function(next) {
var blog_id = $input.val(),
$parent = $input.parent();
console.log(blog_id+' started');
$parent.addClass('synd-in-progress'); //add visual feedback of 'in-progress'
as_process_syndication_to_blog(blog_id).done(function(response) {
console.log(response);
console.log('finished'+blog_id);
$parent.removeClass('synd-in-progress');
next();
});
});
});
$container.dequeue('publish');
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
return as_syndicate_to_blog(data).done(function(){ console.log('end 2nd func'); });
}
function as_syndicate_to_blog(data){
return $.ajax({
type : "post",
dataType : "json",
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id}
});
}
I don't have a test environment for this so you may need to tweak it for your use case.

$.get() does not work?

UPDATED!!
The code after
$.get(url, { id: id, action: action }, function(data) {
does not fire? Complete method below.
function modifyPermit(id, action) {
var url = "ajax/permit_modify.aspx";
$.get(url, { id: id, action: action }, function(data) {
if (data == "SUCCESS") {
// Update page
$.get("ajax/permit_getall.aspx", function (data) {
$("#ctl00_ContentPlaceHolder1_permitList").html(data);
}).error(function(err) {
alert(err);
});
} else {
alert(data);
}
});
}
Using .Net.
Regards,
Robert
You seem to be using a wrong variable for the url here (you defined url_mod but used url in your AJAX request):
var url_mod = "ajax/permit_modify.aspx?id=" + id + "&action=" + action;
$.get(url, function(data) {
which should should become:
var url = "ajax/permit_modify.aspx?id=" + id + "&action=" + action;
$.get(url, function(data) {
Also instead of manually having to call the encodeURIComponent function for each parameter (which by the way you forgot to do in your second AJAX request) I would recommend you using the following construct:
var url = 'ajax/permit_modify.aspx';
$.get(url, { id: id, action: action }, function(data) {
This way jQuery will take care of generating the properly encoded url. The same concept could be applied in your first AJAX request. Notice how you could pass as second parameter to the $.get function key/value pairs that jQuery will use to construct the proper url.
UPDATE:
After having an offline chat with the OP it turned out that the problem was not related to the AJAX code shown in his question but rather with the way he was calling the modifyPermit function. It was inside the onclick handler of a button without returning false. This in turn triggered a full postback to the server leaving no time for the AJAX request to execute. The correct solution was to return false to prevent the default action of the button:
onclick="modifyPermit(1,'a'); return false;"
Fix found by #darin which tuned out to be simple: just add return false; after the method call on the button.
modifyPermit(1,'a'); return false;
Many thanks to Darin for all the time and effort he put in the helping me solve this issue. Could not have don it without you!
/Bob

Why isn't my callback being called on one page only?

I am using jQuery to grab some JSON and then plug it into some elements and display it on my page.
It works fine on all pages except one, where the response seems to be the page itself.
I have placed alert()s in the callbacks (success and complete) and they never seem to be fired (though Firebug shows the request returning 200 OK which should trigger the success handler).
I don't know what to do, I've never encountered this before.
Here is the jQuery code I am using:
var specials = (function() {
var specials = false,
specialsAnchor;
var init = function() {
specialsAnchor = $('#menu-specials a');
specialsAnchor.click(function(event) {
event.preventDefault();
if (specials != false && specials.is(':visible')) {
hide();
} else {
show();
}
});
};
var load = function(callback) {
specialsAnchor.addClass('loading');
specials = $('<div />', { 'id': 'specials' }).hide().appendTo('#header');
var specialsUl = $('<ul />').appendTo(specials);
$.ajax(specialsAnchor.attr('href'), {
dataType: 'json',
success: function(data) {
$.each(data, function(i, special) {
specialsUl.append('<li><h4>' + special.heading + '</h4><p>' + special.content + '</p></li>');
});
specialsAnchor.removeClass('loading');
callback.call();
}
});
}
var show = function() {
if (specials == false) {
load(show);
return;
}
specials.slideDown(500);
}
var hide = function() {
specials.slideUp(500);
}
$(init);
})();
What is going on?
I noticed that you're including jquery.validate on this page, but not the others. jQuery validate with jQuery > 1.5 causes some issues with AJAX calls.
I realize the linked question/answer aren't exactly what you're seeing, but I've seen all kinds of weird issues with AJAX calls and this combination of validate and jQuery, so I figured it would be worth mentioning.
Hope that helps.
This is probably not a complete answer, but could be a step in the right direction. Using Charles Proxy it seems on your other pages when I click specials, it makes a request to http://www.toberua.com/~new/specials however on the contact-us page the ajax request is instead going to http://www.toberua.com/~new/contact-us (which of course is not json)
One other interesting note:
The XMLHttpRequest on other pages sets the Accept header properly (i.e. Accept application/json, text/javascript, */*; q=0.01 , whereas on the contact-us page it is set to Accept */*). I'd bet there's a different code branch being invoked...

Categories