load() API call function callback scope - javascript

I have been coding in JS for a while now, but somehow I always get a bit of a 'scratch head' type of problem. I think that I need to do some digging in, but in the meanwhile can someone help with this one?
So here is the problem:
I am passing through the item (got by $(this)) into the callback function. This code does not work - when I really think it should. Since I have placed the $(this) into a variable (cloning the data?) and then passed it into the callback through a function, surely it should not loose the data? But it does, and horribly
// Allow hrefs with the class 'ajax' and a rel attribute set with a selector to load via ajax into that selector.
$(".ajax").unbind("click").click
(
function(e)
{
var locationhint = $(this).attr("rel");
var $location = $(locationhint);
$location.html ("<img src='images/blockloading.gif' />");
$location.load($(this).attr("href").replace("index.php", "ajax.php"), '', function($location){dready($location);});
e.preventDefault();
}
);
Now that doesn't work.
This one works:
$(".ajax").unbind("click").click
(
function(e)
{
$("#myspecificdiv").load($(this).attr("href").replace("index.php", "ajax.php"), '', function(){dready($("#myspecificdiv"));});
e.preventDefault();
}
);
I take it it's a scope problem, but I have also done this, which should work because it's exactly the same as the 'static' one above, essentially, because it's passing the text ID of the element. This one also breaks:.
$(".ajax").unbind("click").click
(
function(e)
{
var locationhint = $(this).attr("rel");
var $location = $(locationhint);
$location.html ("<img src='images/blockloading.gif' />");
var locationid = "#" + $location.attr("id");
$location.load($(this).attr("href").replace("index.php", "ajax.php"), '', function(locationid){dready($(locationid));});
e.preventDefault();
}
);
The broken ones, when I console.log locationid, return the internal HTML of the target DIV. $location.attr("id"); can't return raw HTML when there is no call to it anywhere else surely? So it's scope I take it? But then how is it getting the internal HTML to spit out?
Any solutions?
Update:
12 seconds after I posted this it occurred to me that function($location){dready($location);} the internal function on the callback might automagically pass the AJAX call response through? But why?

You cannot do this function($location){dready($location);} but you do not need to since the outer scope has $location defined the callback func will understand this var without trying to pass it into the callback funcion so in this instance
function(){dready($location);}
will work.
Another way to conquor scoping issues is to use $.proxy. This allows you to set the this context under which the function will be called. jQuery.proxy( dready, $location ) returns a function that can be used as a callback which when invoked will call the method dready with this set to to $location.
e.g
$location.load($(this).attr("href").replace("index.php", "ajax.php"), '', jQuery.proxy( dready, $location );});

Related

Event function triggering when passing div ID

I'm trying to write some Javascript that when a div is clicked, a function is called with the parameter of that divs ID, the function works when I just send the hardcoded div id like so:
$('#areaOne').on('show.bs.collapse', onSectionClick('#areaOne'));
function onSectionClick(){
var x = $('#areaOne).hasClass('toggled') ? 'false' : 'true';
console.log(x)
}
However when I try it like this:
$('#areaOne').on('show.bs.collapse', onSectionClick('#areaOne'));
function onSectionClick(secID){
var x = $(secID).hasClass('toggled') ? 'false' : 'true';
console.log(x)
}
Then the function is called as soon as the page is loaded, rather then when the area is clicked. I want it to work this way as there are many areas that should trigger the same function.
I'm pretty new to Javascript so any help, or advice on how to do this in a better way would be greatly appreciated.
The problem is that you call the function instead of giving a function reference. Try:
$('#areaOne').on('show.bs.collapse', function(){onSectionClick('#areaOne')});
THe line
$('#areaOne').on('show.bs.collapse', onSectionClick('#areaOne'));
calls onSectionClick, passing in '#areaOne', and passes its return avlue into on, exactly the way foo(bar()) calls bar and passes its return value into foo.
If you want to set it up to be called by the event, you pass a function reference rather than calling the function, e.g.:
$('#areaOne').on('show.bs.collapse', function() { onSectionClick('#areaOne'); });
In your case, though, you probably don't even want to do that. Instead:
$('#areaOne').on('show.bs.collapse', onSectionClick);
// Note no () -------------------------------------^
...and in onSectionClick, use this.id to get the ID of the clicked element ('areaOne' — add the # if you need it).
And if you have other "areas" that you also want to hook up, you can hook them up all at once:
$('selector-for-all-the-areas').on('show.bs.collapse', onSectionClick);
...and then you know which one relates to the event by which element this refers to in onSectionClick.

How to pass `$(this)` as parameter to a "callready" function in Javascript

The leanModal function triggers a modal with some parameters. One of this parameters is a function (ready) that will be executed once the Modal is open. The point is, I need to do some stuff inside that function (ready) just with the element (tag) which triggered the modal, so I need to pass $(this) as parameter to that function. The leanModal() function is provided by MaterializeCss which's the framework that I'm using.
I've been trying this, but thisTag is always undefined. I also have tried to pass directly $(this) to the function, but it also doesn't work at all, it's still undefined. So, how can I reach this?
$('.modal-trigger-editMedic').leanModal({
thisTag: $(this),
ready: function(thisTag){
var refereeNum = thisTag.siblings("[name*='refereeNumToEdit']" )[0].value;
$('#surname').val($("input[id*='medicNameToModal"+refereeNum+"'").val());
}
});
Following the source code, .leanModal supports a ready function (which is triggered once the modal is visible) but doesn't bind or send the element which triggered the modal, the easiest way to fix this is to store a reference outside. To do so, you need to iterate over the triggers yourself instead of relying on that functionality of provided by this jQuery plugin.
Like so:
var $surname = $('#surname'); // you should store the selector as a reference
// outside the loop for better performance
$('.modal-trigger-editMedic').each(function() {
var $this = $(this); // this is the current item in the set of elements,
// therefore our trigger element
// EDIT: using var makes this a local variable
$this.leanModal({
ready: function() {
var refereeNum = $this.siblings("[name*='refereeNumToEdit']" )[0].value;
$surname.val($("input[id*='medicNameToModal"+refereeNum+"'").val());
}
});
});
When you are inside the leanModal it becomes this. Try setting a var to $(this) and pass that through.
var that = $(this);
$('.modal-trigger-editMedic').leanModal({
thisTag: that,
ready: function(thisTag){
var refereeNum = thisTag.siblings("[name*='refereeNumToEdit']" )[0].value;
$('#surname').val($("input[id*='medicNameToModal"+refereeNum+"'").val());
}
});

How to know what parameters are available in jQuery callback functions, how to understand it and add parameters?

I am currently developing a map with the Openlayers 3 library and need to understand the callback functions.
I then started reading and found out I've been using callback functions with jQuery all the time.
I also read that you can use parameters that are available in these functions:
$('body').click(function(e){
e.preventdefault();
)}
The 'e' can be used in the function.
My questions are:
How to know what parameters are available?
Can you add parameters to this function?
Where are these parameters defined?
I am trying to understand this because I would have to use global parameters otherwise, and using global parameters is considered 'bad practice', right?
EDIT:
So if I want to add an extra parameter to the function above, will this work:
document.ready(function(){
var data = 6;
$('body').click(function(e, data){
e.preventdefault();
console.log(data);
})
})
The parameters to the callback functions are documented in the specific API you're using.
For example, the reference for the click-method in jQuery can be found here: https://api.jquery.com/click/
If you want to add parameters to the function you can use variables from outside the function, they will be available inside that function:
document.ready(function(){
var data = 6;
$('body').click(function(e){ // Note: don't add 'data' in the parameter here, it will overwrite your local variable with whatever jquery passes to the function.
e.preventdefault();
console.log(data); // data = 6, it's available from the outer function
})
})
Since the callback will not be executed when you attach the handler (aka when you call $("body").click() sometimes you will need to make sure the variable that is available when executing has the same value as when the handle was attached.
Say you have the following declaration:
var data = 6;
$('body').click(function(e){
e.preventDefault();
console.log(data);
});
data = 10;
In the above case, the console.log(data) statement will output 10. Why? Because by the time the user clicks, the last statement will already have executed and that will have modified data to hold the value 10.
To fix this issue, you need to capture the variable inside a closure:
var data = 6;
$('body').click((function(myVar){
return function(e){
e.preventDefault();
console.log(myVar);
}
})(data));
data = 10;
Here, the value 6 will be logged to the console. Why? Instead of passing a plain function to the click-handler, you're declaring a function and immediately executing it like this:
(function(){
})()
From this IIFE(immediately invoked function expression), you return another function that will be used as the handler for the click event. The variable you pass in to the IIFE will be captured and will keep the same value as it was when you attached the click-handler

Using $(this) & event in named handler function

I have this function:
function showPost(event){
event.preventDefault();
$(this).parent('article').animate({width:'100%'}, 'slow');
}
I am attempting to use it like so:
$('.article-header').click(function(event){showPost(event);});
When I use it in the above manner, the event property is passed just fine, however $(this) doesn't work within the function. If I attempt to include this as a parameter in the .click method, it returns an error claiming this is undefined. I have even gone so far as to set var ths = $(this); to no avail.
Please, what is the proper way to make this function happen?
Just use the function directly:
$('.article-header').click(showPost);
You're loosing this because you're calling the function "naked", with no object receiver. You could do this too (but don't because there's no point here):
$('.article-header').click(function(event) { showPost.call(this, event); });

Javascript scope help

I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}

Categories

Resources