I've read the answers here and here that describe how to read the value of jQuery ajax settings. My question, however, is this:
if I have previously invoked the ajaxSetup function with settings, like $.ajaxSetup({cache: true}), and then I invoke $.ajaxSetup() (with no arguments), are there any side effects to this invocation?
Or more bluntly, does calling $.ajaxSetup() with no arguments do anything other than return a plain object that contains the settings for ajax?
The answers I've referenced above both call ajaxSetup in this way in order to read the value of a setting, and I have been unable to find any official answer on the jQuery docs that indicate what calling ajaxSetup with no parameters does, probably because its use is so heavily discouraged.
In my browser, I ran a simple test by loading jQuery, running $.ajaxSetup({async: false}); followed by $.ajaxSetup(); and found that the value of async was still unchanged (the default value is true, and so if calling $.ajaxSetup() resets the settings to default values, then the value of async should have been changed), but this probably isn't a strong enough evidence to conclude that side effects do not occur when the function is invoked in this way.
Does calling $.ajaxSetup() with no arguments do anything other than return a plain object that contains the settings for ajax?
No.
Example
// set a new custom url
$.ajaxSetup({
url: 'CHANGED'
});
// call it again with no params
$.ajaxSetup();
// the url is still the custom url
console.log('url: ' + $.ajaxSetup().url);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Why?
If we look at the code for ajaxSetup, we see that, when called with a single parameter, it returns the call:
ajaxExtend( jQuery.ajaxSettings, target );
where target is the single argument you passed into ajaxSetup().
Now, inside ajaxExtend, we can see that it tries to iterate over that same argument with a for in loop.
Relevant code:
function ajaxExtend( target, src ) {
for (var key in src) {
// here is where target, which in this case is jQuery.ajaxSettings, gets overriden
}
return target;
}
Since you don't pass anything, basically you are doing
function ajaxExtend( target, src ) {
for (var key in undefined) {
// this is never reached
}
return target;
}
which never enters the for in loop and returns the current value of jQuery.ajaxSettings.
Related
I've seen lots of questions and solutions to problems like this but nothing has worked for me. I have this:
function() {
$("#bdiv").load("bosses.php #icc10n",function(){
return $("#bdiv").html();
});
}
But it's not working. To clarify, I want to load content into #bdiv and then return the contents of #bdiv. But it seems that $("#bdiv").html() is being returned before the content is loaded even though I've put it in a callback function.
$("#bdiv").load("bosses.php #icc10n",function(data){
// use the data param
// e.g. $(data).find('#icc10n')
});
as far as I know you cannot make a return statement in the callback function of a $.ajax(), $.post(), $.get(), etc.. method. You could, however, store the 'data' value in a variable declared outside the function, and then set the value of that variable when the callback function executes. And there is a variety of other options.
You can't do that.
AJAX is asynchronous, meaning that your function will return before the server sends a response.
You need to pass the value to your caller using a callback, the way $.load does.
I have a utility function to insert HTML into a div and then call a javascript initializer function that attaches event handlers to various elements in the inserted HTML. The functions works great for 90% of cases but periodically fails in the jquery html() call below. When it fails, the HTML is inserted properly but the code on the next line is never reached.
function loadSection(id, url, initializer = null, param = null) {
const $div = $('#' + id);
return $.ajax({
method: 'GET',
url: url,
})
.done(function (html) {
$div.html(html);
if (initializer) { // This line is never reached.
initializer(param);
}
});
}
The same failure occurs if I use $div.empty().append(html) instead of $div.html(html) so the problem isn't in the html() function itself. In fact, if I step through the html() code, it executes this.empty().append(value) and never returns to the calling function.
The html that is inserted may contain to set variable values but does not call any javascript functions directly.
I've done a pretty exhaustive search of StackOverflow and the web but have come up empty. I've also traced through the jQuery code but couldn't identify the issue. Can anyone tell me why this is failing?
Answers to some of the questions:
It IS deterministic. The failure cases always fail and vice versa.
I know the code succeeded because code execution gets to $div.html(html). And the html returned in the GET is correct.
Example of how this is called:
function loadNewContracts() {
loadSection('prospector-newContracts', '../newContracts', initNewContracts);
}
The initializers are different for every section. The key points is that the initializer is NEVER called.
The correct initializer IS being passed into the function and does exist.
The only tags in the HTML set variable values. No js functions are called. Calls that succeed also set variable values. There are NO loops in the tags.
The $div variable DOES exist in all cases.
Barmar was close and gave me the idea to figure this one out. The js variables being set in the html are generated in a jinja2 template. A non-existent value was being passed to the template so the script ended up looking like ...
var currentValue = ;
... so the js fails while loading the html. Another one failed in an similar manner. These failed because of recently introduced bug in the server code.
Obvious in retrospect but I overlooked it because you can't break on the js in the . Thanks, Barmar!
Not sure if this is a dumb question. I've started playing with a few JavaScript frameworks and I always get confused when I see an argument that is not being used inside a function.
A Backbone example (the model arg):
var Todo = Backbone.Model.extend({
validate: function(attribs){
if(attribs.title === undefined){
return "Title can't be undefined";
}
},
initialize: function(){
console.log('This model has been initialized');
this.on('error', function(model, error){
console.log(error);
});
},
});
Express example (the req and next args):
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
So, I'm wondering, those values are just ignored? What would happen if you leave them out? And why they have to be included in the first place? (I'm used to the idea that if a function passes an argument is because it will be used in the function).
In the case of initialize:
The variable model isn't used, but error is. Because error is the 2nd argument, model must be passed as a place holder.
The same thing is true in use:
The variable req isn't used, but it is required as a place holder so res can be used.
Why do the functions have parameters that don't appear to be used?
Maybe it's for backwards compatibility or for extensibility.
I assume these are both open source libraries (I've never used either).
If those values are ignored, nothing would happen and it would work good as well.
Whether those values are ignored or not, whether you use them or not, they are passed in actually.
You dont have to, unless you are using an argument that is after the an argument you dont use.
And even then , you could use the argument object in a function to get the argument at the right index.
function myFunc(){
console.log(arguments);
}
myFunc(1,2,3,4,5,6); // logs 1,2,3,4,5,6
In a documentation , though , it is better to let the developper know what arguments are injected in the callback so the developper can have a clear view of the continuation configuration.
You are correct that these arguments will be ignored if you do not use them. Also, they can be safely left out. But, if you only want to access the second argument you will need to have the first there as a placeholder.
As to why these arguments are there? It is important to understand that what you are passing in is a callback function. This callback is then called at a later point by the function that you passed it into. So it is the function provided by the framework that is calling your callback function and passing in these arguments. The Framework has no way of knowing what your specific use case is and has know way of knowing exactly what data your callback needs. Thus the authors of the framework pass in several arguments with enough data to cover as many use case as possible. While your callback function is not making use of these arguments other developers using these frameworks might be writing a callback that does.
I'm having issues passing parameters/variables into the ajax() function.
The function below accepts two parameters. One is 'element', the success option of .ajax() uses, that works fine so no need to focus on that. The 'tx' is either a single value like 'menu' or a couple of values separated by a colon like this: "menu:categories:brands"
If there is only one value in 'tx' then only one AJAX request needs to be sent and that works fine. If there is more than one value in 'tx' the function split's it using ":" is the delimiter and then passes offset[0] as the value of 'tx' into the AJAX request and then store's the rest of the values in 'x'.
What I'm having issues with is running this function recursively once the AJAX request is complete for the first value. The var 'more' stores a bool value if there is more values left to process or not. However, when I write in an if argument using 'more == true' into the success or complete option of .ajax() it doesn't reflect the value stored in that variables, it always returns false.
Before some one answers, with "You should structure the function that calls this function to only pass a single value into that parameter," lets suppose that this is an impossible venture that is outside the realm of my control.
I have no idea why this happening. I know it's probably something very simple that I'm overlooking but I've been up for about 16 hours now and this issue has plagued me for at least half that time.
Any help here is appreciated. Here is the function:
function getContent(element, tx) {
e = element
modAmount = tx.split(':')
if (modAmount.length > 1) {
x = ''
tx = modAmount[0]
for (i=1;i<modAmount.length;i++) {
x = x + modAmount[i]
if (i != (modAmount.length)-1){
x = x+":"
}
}
more = true
}
else {
more = false
tx = modAmount[0]
}
$.ajax({
type: "POST",
url: "getModule.php",
data: "modName="+tx+"&DB=<?php echo DB ?>",
success: function(data){
if ($( element ).find('p').text() == "No Content"){
$( element ).find('p').remove();
$( element ).html("<div onclick='destroy(this)' id='destroy' class='ui-corner-all destroy' title='Remove Module'>"+data+"</div>")
}
else {
$( element ).append("<div onclick='destroy(this)' id='destroy' class='ui-corner-all destroy' title='Remove Module'>"+data+"</div>");
}
},
complete: function() {
if (more == true) {alert(x)} // always returns false
}
});
}
There's already one glaring error here: you're not declaring your local variables using the var keyword. This means that there's only one instance of any of those variables, in the global context.
I'm not sure if this is your problem, but it certainly seems like it could be. Consider the case where you call getContent "foo:bar". The first call sets more to true, but then the second recursive call sets more back to false. When the first XmlHttpRequest finishes, the completion callback will see the value of false rather than the true you were expecting, since those two calls are sharing the same variable for more.
You should read up on how JavaScript/ECMAScript scoping works, and gain a solid understanding of how closures work in the language. This will prevent a lot of head-scratching in the future. Google around for writings by Douglas Crockford; that's a good starting point.
tl;dr: define your local variables using the var keyword.
Because "more" isn't scoped within your callbacks.
I recommend using the context property you can send to the ajax call to set the "this" variable in success/complete callbacks:
http://api.jquery.com/jQuery.ajax/
I'm using hoverIntent which, as part of its settings, will call a function. I think this is called 'referencing a function' (correct?):
var HIconfig = {
interval: 250,
sensitivity: 8,
over: myFunction,
timeout: 100,
out: myOtherFunction
};
However, I'd like to reuse said function at times and explicitly pass in a jQuery object. So, I added that to the function.
myFunction($myObject){
}
The challenge now is to figure out when the function is being referenced by hoverIntent or being explicitly called. My thought was that I'd check to see if $(this) contained a particular DOM element:
myFunction($myObject){
if($(this).is('li')){
$myObject = $(this)
};
$myObject.doSomething...
}
But...I'm having issues. If I log out both $(this) and $myObject these are the results:
Called via hoverIntent:
$(this) = [li#Trigger-0.nav-main-tab]
$myObject = Object { originalEvent=, more...}
Called via explicitely passing an object
$(this) = [Window PT02-home-page.php#]
$myObject = [li#Trigger-0.nav-main-tab]
I can test for $(this).is('li') in the first scenario, as it's true.
I can't in the second, though, as when I try to perform the test, Firefox doesn't like it:
g.nodeName is undefined
One suggestion was to switch to 1.4.1 and try to test for the opposite via .isPlayObject:
if (jQuery.isPlainObject($myObject))...
This works just fine in Firefox. However, IE8 always returns true.
My questions:
Is my logic simply way off in terms of how my function gets called from hoverIntent vs. directly?
If not, is there a way to consistently test to see if I have explicitly passed in an object to my variable in the function?
I would do this totally differently. First, it's weird to have a function take a jQuery object as a parameter. Go the jQuery way and make your function into a jQuery plugin. For use in your hoverIntent configuration, you can either wrap your function in another little function, or do that with the new (1.4) jQuery.proxy() function.
Instead of passing an object, why not pass a simple boolean to indicate where it has been called from, for instance:
myFunction(asOption){
if(asOption) {
alert("called from hoverIntent");
} else {
alert("called from somewhere else");
}
}
or am I completely missing the point?
You're making this unnecessarily complex. Just use a wrapper for the callback that passes the argument the function expects:
var HIconfig = {
interval: 250,
sensitivity: 8,
// myFunction expects a jQuery object, so create one from the context
over: function() { myFunction($(this)) },
timeout: 100,
out: myOtherFunction
};
...then you can skip the check inside your function altogether:
myFunction($myObject)
{
$myObject.doSomething...
}