jQuery callback issues, it runs just once - javascript

I am having some issues with a piece of code, I use jQuery's ajax to load search results, because its a list I wanted to style the list, zerbra style, so I have included a callback function. The following works the first time but when I search again it doesn't work (styling).
When I put an alert in the callback function it fires every time, but the styling doesn't work.
ajax part
$.post('search.php',{value:val}.function(data){
// output list
}).error(function(){
// error output
}).success(function(){
// callback function.
if(typeof options.afterLoad == 'function'){
options.afterLoad.call(this);
}
});
the plugin options
$('#search').search({
afterLoad: function(){
$('#results').children('li:odd').addClass('odd');
}
});
This isn't the complete plugin, but just the parts that matter.

If the callback is executed then I can think on 3 options:
There is no control with id results
There is no children li for #results
Class odd doesn't exist or it doesn't containst the style rules you suppose it has (maybe a cache issue?)
Put a debugger instruction on the callback and check the length of $('#results') and $('#results').children('li:odd')

Related

Can I make Javascript always call a method after JQuery Load?

We have started using jquery load in our site to load contents into a div rather than re-loading whole page. However in the complete function we have a method that re-applies various bindings. Is it possible to provide load method with a default complete function? So developers don't have to specify it in the jquery load complete function.
As we currently are providing a lot of duplicate complete functions
E.g.
$('#Target').load(callBackRedirect, function () {
ApplyBindings('#Target');
});
These bindings can't be applied using on and need to be re-applied on page loads. We also do some other work that we want to do on every page load.
The answer is no.
You need the callback because that's what the method calls when the request is done.
This works with on method to, you might be doing something wrong out there in the code.
You could create a helper function for this.
function loadSomething(targetElement, uri,callback) {
targetElement.load(uri, callback);
}
loadSomething(
$('myElement'),
'mylink.com/content',
function() {
applyBindings($(this));
}
)
Yes. Check out the list of Global AJAX Event Handlers.
e.g.
$(document).ajaxComplete(function() {
alert('Triggered ajaxComplete handler.');
});
That said, you shouldn't need to reapply your bindings after an AJAX call. If you need to do this, you're probably doing something wrong. Check out jQuery.on, which explains how to bind to content which is added dynamically.
Try $.ajaxSetup:
$.ajaxSetup({
complete: function() {
ApplyBindings('#target');
}
});
EDIT
You could also make a named function like:
var ajaxApplyBindings = function() {
ApplyBindings('#Target');
// anything else...
};
And then pass it to load:
$('#Target').load(callBackRedirect, ajaxApplyBindings);

Ajax .load() won't work when triggered initially

So I have a simple tab system which I handle with the .load function to load the desired content. The problem is that the page itself which contains this tab system is a ajax loaded content. And for some reason the initial call of the tab function to display the initial tab content won't work. But after manually choosing a tab, the load function loads the content properly.
her some code to look at:
The tab handler:
function loadTab(tab) {
$(".tab_a:eq("+otab+")").removeClass("tab_slc");
$('#tab_content').hide();
$('#tab_content').load("include/tab_downloadVersions.html .tab:eq("+tab+")");
$(".tab_a:eq("+tab+")").addClass("tab_slc");
$('#tab_content').fadeIn(function() {});
otab = tab;
}
at the end I call loadTab(tab); and the thing should be initialized. but for some reason the content remains empty. As soon as you manually click on a tab (I have an on click function which calls loadTab(tab) everything starts working)
Because the code by itself works, I think the problem is caused by the other script which handles the page itself. It is also a .load function which loads the page, which loads this tab system.
So do multiple .loads don't like each other? and if so, what can I change?
Thanks in advance ;)
EDIT: I could't post the entire code for some reason, but if you go here you can see the site in action with all the scripts:
n.ethz.ch/student/lukal/paint.net
The tab system is on the download page.
EDIT:-----------------------------------------------------------------------------------------------------------------------------
Big Update
So this is still the same issue but with a slight twist: I did what was recommended in the comments and put my secondary .load() call inside the success call of the first one.
$("#content").load("pages/contact #contentInside", function() {
$("#OtherContent").load("include/info #OtherContentInside");
});
So this works.
But now I had the great idea to make a giant load function. It is a slightly better function than just the plain load, cause it does some fading and stuff. But now I have the same problem, but even more complicated. I created the load function as a "plugin" so the function itself is in a different script file and therefore I can't access the inside of the success function. I solved this problem with a return $.ajax(); and a .done() call. The problem here is that there is some rare case where it just skips the secondary load function. So I am searching for a guaranteed way of controlling the order of the .load calls. Any idea?
The mock-up website is up to date with the new scripts if you wish to take a look. And people were complaining about potential virus spread from my link. For some reason I can't post long code snippets so the site is the best source I got to show everything. If you know a more trustworthy way to share my code please let me know.
We cannot see the rest of your code to tell where the initial call is being invoked from. A set up like the following should work:
$(function() {
var tab = 0;
loadTab( tab );
});
function loadTab(tab) {
//WHAT IS otab???
$(".tab_a:eq("+otab+")").removeClass("tab_slc"); //<<<==== otab
$('#tab_content').hide();
$('#tab_content').load("include/tab_downloadVersions.html .tab:eq("+tab+")");
$(".tab_a:eq("+tab+")").addClass("tab_slc");
$('#tab_content').fadeIn(function() {});
otab = tab;
}
Update
The reason it does not work initial is because otab is not defined the first time the function is called. You have initialized otab at the end of the function but you are using it at the beginning of the function.
UPDATE 2
I have had a chance to look at your code and I just found out what the issues are:
You do not have DOM ready
You are not calling the function on page load.
The following version of your code should work -- try not to use global variable as you're doing with otab. Since you're loading this script at the end of the page (an you are using event delegation) you may get away with DOM ready. Adding .trigger('click') or click() as indicated below should resolve the issue.
//Tab-loader
//Haeri Studios
var tab = 0;
var otab = tab;
var counter = 0;
//click detect
$(document).on('click', '.tab_a', function() {
tab = counter == 0 ? tab : ($(this).attr('id'));
loadTab(tab);
counter++;
return false;
})
.trigger('click'); //<<<<<===== This will call the function when the page loads
//Tab setup
function loadTab(tab) {
//Content Setup
$(".tab_a:eq("+otab+")").removeClass("tab_slc");
$('#tab_content').hide();
$('#tab_content').load("include/tab_downloadVersions.html .tab:eq("+tab+")");
$(".tab_a:eq("+tab+")").addClass("tab_slc");
$('#tab_content').fadeIn(function() {});
otab = tab;
}
//Initialize << WHAT ARE YOUR INTENTIONS HERE .. DO YOU REALLY NEED THIS PIECE?
$.ajax({success: function() {
loadTab(tab);
}});
A partial answer to this problem was to call the loadTab function inside the success call of the page load function, like charlietfl pointed out. But the problem is that there is no need to call the tabloader every time a new page gets called. So I would rather not have a rare call in every page setup function.
I am a bit disappointed by the system on stackoverflow. It seems like if you have not a high reputation level, no one gives a "S" about your questions. Well but at least some input was give, for which I am very thankful.
So by digging deeper into google I found out that the callback can be manually placed in the function where ever you like.
so if we have a function:
foo(lol, function() {
//This after
});
this does stuff after foo() is done. But what if we have another function inside foo() which we also need to wait for:
function foo(lol) {
bar(troll, function() {
//This first
});
}
The bar function is not relevant to the success call of foo. This causes the unpredictable outcome of calls.
The trick is to control when the success function of foo gets called.
If we add a parameter(callback) inside foo and call this "parameter" (callback();) inside the success call of bar, we can make sure the order is guaranteed.
And that's it:
function foo(lol, callback) {
bar(troll, function() {
//This first
callback(); //<-This callback placement defines when it should be triggered
});
}
foo(lol, function() {
//This after
});
We get:
//this first
//this after

"Function factory" doesn't seem to work, JavaScript

I'm displaying a series of images in a loop, and I'm trying to implement some sort of nudity filter so I'm using nude.js, a library that can somewhat detect nudity. Here's the code:
// we're inside a loop
$(".images").prepend($("<img>").attr({src: whatever, id: uniqueid}).load(function(e) {
nude.load(e.target.id);
nude.scan(function(result) { if (!result) $(e.target).detach(); });
});
However, it detaches all of the wrong images because nude.js is slow and it completes after the loop has gone on to the later iterations, detaching those images instead of the one it was working on.
I've tried using a function factory:
function generateCallback(arg) {
return function(result) { if (!result) $(arg).detach(); };
}
and
nude.scan( generateCallback(e.target) )
but the same thing happens.
What I want is a load event that will remove the image if it seems to contain nudity. How can I do this properly?
EDIT: nude.js works like this:
nude.load(imageid);
nude.scan(callback); // it'll pass true or false into the callback
another edit: accidentally omitted the id setting from the code I posted, but it was there in my real code, so I added it here.
I suspect the case here is that this kind of sequential processing won't work with nude.js.
Looking at the nude.js code, I think your problem is occurring in the call to nude.scan. nude.js has a variable that stores the function to invoke after the scan has completed. When calling nude.scan(callback), this variable is set to be callback.
From your PasteBin, it seems as though the callback gets assigned as expected on the first call, but on the second and subsequent calls, it gets replaced, hence why the second image is detached and not the first.
What happends to your script, is that the e var is global to the function and so after each loop it gets replaced with the new one. So when the first image is scanned, e already became the event of the second image, which get detached.
To solve your problem, use closures. If you want to know more about closures, have a look here.
Otherway, here's the solution to your problem :
$(".images").prepend($("<img>").attr({src: whatever, id: uniqueid}).load(function(e) {
(function(e) {
nude.load(e.target.id);
nude.scan(function(result) { if (!result) $(e.target).detach(); });
}) (e);
});
EDIT: AS nick_w said, there is var that contains the callback and probably gets replaced each time so this is why it isn't the right picture getting detached. You will probably have to modify the script yourself

Jquery DOM events called after events following it are executed

I am facing a very weird issue in chrome.
My code is
$('#import').text("Importing...");
$('#import img').removeClass("hidden");
Server.postService("tests", row_datas, function(data) {
// some stuff here
});
The text and the hidden class are being removed after the post action has been executed.
The code is working fine in firefox.
The only thing needed was
Server.async = true
before the server call.
Asynchronous functions fire in order of appearance but return in order of when they finish. It would be odd for those simple text and removeClass methods to return more slowly than whatever you're doing with your Server object, but I suppose it's possible. If you need the first two lines to happen before the postService, you might try jQuery's deferred.promise. Here's a fiddle demonstrating the potential, and some code to inspect:
function firstThing (){
var dfd = new jQuery.Deferred();
$('#import').text("Importing...");
$('#import img').removeClass("hidden");
dfd.resolve();
}
$.when( firstThing() ).then(
function() {
Server.postService("tests", row_datas, function(data) {
// some stuff here
});
}
)
As a side note, the logic of your code is problematic in that by setting the text of #import, whatever img had the hidden class won't be there anymore, but that might be beside the point.
Update
Noticing your response to my comment asking about your use of ajax, I would suggest you read about the async option and see how what you're doing might or might not be blocking events.
I would also recommend reading about jQuery ajax callbacks, particularly error, success, and complete (now, with jQuery 1.8+, fail, done, and always).

How do I set up sequences of functions that I want executed in JavaScript?

I'm working on a JavaScript driven site where I will have a lot of stuff that need's to be executed in a certain order. A lot of the stuff involves animations and AJAX-loading. Some pseudo code could look like this:
Load JSON formated data
Generate HTML-elements using the loaded JSON data and render them inside a div
Make the elements inside the div scrollable using a jQuery UI slider
Randomize a number between 1 and the total number of loaded elements
Make the jQuery UI slider scroll (animate) to the element that represents the randomized number for a duration of 500 milliseconds
Load more JSON formated data
Replace other elements on the page
And so on...
Each step in this is wrapped in a function - one function loads the JSON data, another generates the HTML-elements, a third initializes the jQuery UI slider and so on. Encapsulating the code in functions makes the code easier to read for me, but above all I want to be able to call the functions in different orders depending on what happens on the page and I want to be sure that one function has finished running before the next one is executed.
If there was just regular functions that didn't involve AJAX or jQuery animations I'd just execute the functions I want to execute, one after the other. The problem is that I need to wait for the animations and data retrieving functions to finish before moving on. To aid me both the animation and AJAX methods in jQuery allow me to send along a callback. But here's where I get lost.
What I want it to do is the following:
Load JSON data. If the loading is successful, go on and...
Generate HTML-elements
Make the elements scrollble
Randomize a number between 1 and the total number of loaded elements and pass it to...
A function that makes the jQuery slider slide (animated) to the element. When the animation is finished...
Load more JSON formated data. If the loading is successful, go on and...
Replace other elements on the page
The ideal thing would be if I could set up this sequence/chain of events in one single place, for example inside an event handler. If I want to call the functions in a different order or not call all of them I would just set up a different sequence/chain. An example could be:
Randomize a number between 1 and the total number of loaded elements and pass it to...
A function that makes the jQuery slider slide (animated) to the element. When the animation is finished...
This means that I'd have to be in control over the callbacks in each step.
I hope you understand what I'm looking for. I want to control the entire execution sequence from a single function. This function would be "the conductor of the orchestra" and all the other functions would be the different instrument sections of the orchestra. This conductor functions need's ears so it can hear when the violinist is finished with her solo and can tell the horns to start playing. Excuse me for the corny allegory, but I hopes it makes it easier to understand what I want to do.
Thanks in advance!
/Thomas
Would the jQuery .queue() function help you?
Could you store a sequencer variable that is an array (which you would be able to change) and then call a sequencer at the end of each function?
You could then pass a step code through each function and cross-reference that with the sequencer variable as to what the next step should be.
Pseudo Code:
var func['1'] = function(arg1,arg2,seq) {
//code
sequencer(seq);
}
var func['2'] = function(arg1,arg2,seq) {
//code
sequencer(seq);
}
var func['3'] = function(arg1,arg2,seq) {
//code
sequencer(seq);
}
var func['4'] = function(arg1,arg2,seq) {
//code
sequencer(seq);
}
function sequencer(seq) {
seq = seq + 1;
window.func[seq]
}
I tried executing this code:
var seq = 0;
var func = [];
func[1] = function(seq) {
setTimeout(function() {
console.log("Executing function 1");
sequencer(seq);
}, 2000);
}
func[2] = function(seq) {
console.log("Executing function 2");
sequencer(seq);
}
func[3] = function(seq) {
console.log("Executing function 3");
}
function sequencer(seq) {
seq = seq + 1;
func[seq].call();
}
sequencer(seq);
But the result (in Firebug) is:
Executing function 1
func[seq] is undefined
[Break on this error] func[seq].call();
I think that the problem is caused by context, but I'm not sure. JavaScript is sensitive to the context in which a function is called.
/Thomas
I found that what I was trying to achieve was slightly overkill for my purposes. So I decided to go with a different approach. I can send one or more boolean variables as a parameters to a function and use them to decide whether to execute a second function or not. Here's an example:
$("#justOneStep").click(function() {
loadImage(false);
});
$("#twoStepsPlease").click(function() {
loadImage(true);
});
function loadImage(boolDoMore) {
// Do the stuff that loads an image
...
if(boolDoMore) {
nextFunction();
}
}
function nextFunction() {
// Do some more stuff
...
}
Not very fancy but easy to understand and control and sufficient for my needs at the moment.
/Thomas

Categories

Resources