jquery callback function scope - javascript

when i use jquery to create an element(a div, for example) in a callback function, it doesn't allow me to manipulate the newly created element outside the callback function, how can I get around this?
here is the example:
$.get('menu.xml',function(data){
//create a new element with an ID called "#newElement"
})
//I can't select the element outside the callback function so the following code dosen't work:
$('#newElement').css('background','black');

You can select it outside, but not yet, that $.get() callback takes some time to run (it has to get the data from the server, the callback happens later, when that finishes), so when you do this:
$('#newElement').css('background','black');
That element isn't there yet (and so the selector doesn't find anything...it's running before that callback creating it does), you need to wait until the callback finishes before continuing any code that needs elements created by it. Like this:
$.get('menu.xml',function(data){
//create a new element with an ID called "#newElement"
//kick off stuff that uses "#newElement"
$('#newElement').css('background','black');
});

$.get('menu.xml',function(data){
//create a new element with an ID called ".newElement"
$('<div/>').val(data).attr('id','newElement').css('background','black').append('#container');
})
Try modifying the element within the callback, also try using the class instead of the id

Judging from the code you've shown, it seems your trying to manipulate '#newElement' before it exists. The reason for that is '#newElement' is created in the callback of '$.get'.
Its important to remember that asynchronous functions in javascript don't cause the thread to wait, this is why callbacks exist. So, before your callback function for '$.get' has even been executed, you are trying to manipulate '#newElement'.
For instance, if you adjust your code to:
$.get('menu.xml',function(data){
//create a new element with an ID called "#newElement"
....
$('#newElement').css('background','black');
})
You will find that it works.

Related

Callback on .css function

So, I am familiar with the fact that you cannot use a callback function on jQuery's .css function. Instead, I used the setTimeout function:
$('#header-nav').css({'left': leftBstr});
posBstr = '.level' + posB.toString();
setTimeout(function(e){
$('#header-nav ul' + posBstr).removeClass('menu-active');
}, 300);
This code is meant for a mobile menu animation. There are two typed of buttons:
go further into the menu (child categories)
go back (parent category)
But, when using the setTimeout function, when I click too fast, the menu disappears, because of the removed class menu-active.
I already tried putting the setTimeout function inside a var, and use the clearTimeout function, but that did not work.
My question: is there another way to recreate the callback function on the .css function, without using setTimeout?
You can try to use the promise
The .promise() method returns a dynamically generated Promise that is resolved once all actions of a certain type bound to the collection, queued or not, have ended.
$('.element').css("color","yellow").promise().done(function(){
alert( 'color is yellow!' );
});

How to pass extra parameter to event handling callback?

I have a button on which I want to attach an event listener. I also need to pass a extra parameter url to this function. I read about apply and I'm doing the following:
$('#list-button').on('click',postListing.apply([url]));
My problem is that as soon as this script is loaded postListing is called. I am not calling the function anywhere else. I need it to be called only on click.
The difference between bind and call/apply is that bind doesn't call the function immediately much like it loads the data with the variable when needed
You can reformat your code so it looks like this
$('#list-button').on('click', postListing.bind(this, url));
Found a way. It can be done using a closure:
var postListing = function(event, url){
return function(){
//Main functionality wrapped here
};
};
And the event listener setting remains the same:
$('#list-button').on('click',postListing.apply([url]));

Call jquery function without any particular event handler

How to use jquery functions more similar to javascript ? What i mean about that, is to call a function from script tag in html like do_something()and this will trigger the function.
I have on my jquery script file $(document).ready(function() {... } and it contains some functions with onclick handlers and others, but how to trigger function by just simply inserting name of that function in html, which can be call in some instances while processing code and loading page ?
jQuery is just a JavaScript library. Its functions are JavaScript functions. You can call them in the same way as any other JavaScript function.
Passing a function as an argument to ready just means "When the ready event fires, call this function". It's similar to setTimeout(function () { … }, 5000) only with a condition other than "after 5 seconds".
It sounds like you are having trouble with the scope that $(document).ready(function(){...}) creates;
You will want to place do_something() outside of the $(document).ready(). This will allow your DOM (in html) handlers to call it.
Also keep in mind that $(document).ready() is only used to make sure that the DOM is ready before JS tries to interact with it. If you are placing your JS in the html, the DOM will be ready by the time the functions are called.
You may want to see this question for more details:
Global javascript variable inside document.ready

call javascript callback explicitly

I have two functions, one is for expanding tree view (i.e. ExpandAll()) and second one is for removing particular type of elements from that tree view (i.e. RemoveAbElements()).
ExpandAll() method checks if there are child nodes under the selected node. If not then it retrieves the child elements by ajax call. So now I am calling these methods as follows :
function(){
ExpandAll();
RemoveAbElements();
}
Now my problem here is, there is a callback in ExpandAll() method and it gets called for each child node expanded (which is expected). Now here the callback gets called even after the execution of RemoveAbElements() method. I want to execute ExpandAll() method and all of its callbacks before RemoveAbElements() execution. I tried lots of things for this but none worked. please help.
There could a be lot of ways you could be approaching.
One way could be, passing the RemoveAbElements itself to ExpandAll.
So you could be passing it as
ExpandAll(RemoveAbElements);
or, When you don't want to call RemoveElements, as :
ExpandAll();
And ExpandAll could be modified to accept the callback :
ExpandAll(callbackFunc) {
//... Do Work Here
if(callbackFunc) callbackFunc();
}
Or use triggerhandler & on if there is a jquery object, as suggested by slinky2000.
If I've understood you correctly you need to add a listener to EXpandAll() and when it's finished everything call RemoveAbElements()
I would look at jquerys custom event triggering:
http://api.jquery.com/trigger/
// Listen for finish
$('#tree').on('customFinishedEvent', function(event) {
alert('finished');
});
// On finished loading and expanding
$("#tree").trigger('customFinishedEvent');

JS to monitor the CSS property change like "display:none"=>"display:block"?

I want to run some JS code when an image's CSS property "display" has been changed by any other JS script/functions. Is there any method to monitor that change and setup a callback function?
$(this).bind.('propertychange', function(){})
cannot do this, and setInterval is also a bad idea.
What else could be done?
This is what you are looking for:
document.documentElement.addEventListener('DOMAttrModified', function(e){
if (e.attrName === 'style') {
console.log('prevValue: ' + e.prevValue, 'newValue: ' + e.newValue);
}
}, false);
This is inside the legacy JavaScript files that you do not want to modify:
// this is your original, unmodified function
function originalFunction(sel) {
alert(sel);
$(sel).css("display","none");
}
This is in your code:
// here is a sample callback function you pass into the extended function below
function myCallback(s) {
alert("The image with src = '" + $(s).attr("src") + "' has been modified!");
}
// here is how you can extend the function to do what you want
// without needing to modify the actual code above
originalFunction = (function(legacyFn, callback) {
// 1 arg function to be returned and reassigned to originalFunction
return function(sel) {
// call "original" originalFunction, with alert and image hide.
legacyFn(sel);
if(callback) callback(sel); // invoke your callback
}
})(originalFunction, myCallback);
The variable originalFunction is assigned a function that takes one argument. The function that takes one argument is returned by an anonymous, self-executing function that takes 2 arguments, the reference to the originalFunction before it is modified, and the reference to the callback function. These two function references become "locked" inside the closure so that when the originalFunction is then assigned a new value by the self-executing function, the legacyFn parameter still contains a reference to the originalFunction prior to it being modified.
In summary, at a higher level, originalFunction and myCallback are passed in as parameters to the self-executing anonymous function and are passed into the variables legacyFn and callback, and a new function is then assigned to originalFunction.
Now, when you call originalFunction('.someClassOnAnImage'), the legacyFn will fire, which will alert the selector and set the display property to none. Afterwards, the callback function, if it exists, will fire, and you'll then see:
The image with src = '.someClassOnAnImage' has been modified!
While this isn't as nice as a hypothetical or platform-specific addEventListener, it does allow you to modify the behavior of the functions in the legacy code without having to physically crack open those files and modify them. This simply extends the functions to perform additional behaviors but without needing to modify the original functions or even the original files for that matter.
You could neatly include all of your extensions in a separate JavaScript file (or whatever JavaScript file you're working in) and if you ever want to go back to the original behavior, you simply remove your extended functions.
The Answer: See this other post >> is there an alternative to DOMAttrModified that will work in webkit
The Rant:
The DOM Mutation events hold the key to your problem. However, in the new wave of browser wars, Wekit and Gecko can't agree on stuff. While Gecko has DOMAttrModified, webkit has something called mutation observer (which breaks the pattern of event handlers being attached to events but hey who cares for consistency when we want to lock users/coders in right? ;)
P.S: Just adding this here for future seekers of the same wisdom.
Building upon Jeff's suggestion, I would recommend writing a single function that modifies the image style property and then using that function as the bottleneck that all other functions must go through to modify that image style property.
function showImage(selector, callback) {
$(selector).css("display","block");
if(callback)
callback();
}
function hideImage(selector, callback) {
$(selector).css("display","none");
if(callback)
callback();
}
Something like the above two functions can be invoked from anywhere in your JavaScript when you must change the image CSS property. The functions also take a function as a parameter, which would be executed afterwards assuming the function was passed in as the 2nd parameter.
You could further simplify this into a single function, but I'll leave that to you as I don't know exactly what your goals are in doing this.

Categories