Ajax setting 'context' does not affect 'data's location - javascript

the following Ajax works
function Retrieve(el) {
var table = this;
this.el = el;
this.fetchInfo = function () {
$.ajax('data.html', {
context: table,
<!-- QUESTION HERE -->
data: {
location: table.data('location')
},
success: function (response) {
this.el.find('.info').html(response).fadeIn();
},
}
}
but I am wondering why I cannot replace table.data with this.data on the denoted line. Since I set the context to table variable, this now should be set to whatever table is referring to right? This holds true in the context of other members of the Ajax object (including success), but not for the members of data. Why is this the case?
data('name') extracts value from a tag with attribute data-name

The context variable you've given only applies within the success callback, and doesn't change anything for any of the other parameters passed to $.ajax.
The answer therefore depends on how you actually call fetchInfo. The data: variables will be resolved in whatever context fetchInfo has. Given you're experiencing problems, this suggests that you are not calling the function with your Retrieve object as its context.
EDIT this line is your problem:
this.el.on('click', 'button', this.fetchInfo);
just because you've referred to this.fetchInfo, doesn't make this the context when it's subsequently invoked. Try this instead:
this.el.on('click', 'button', $.proxy(this.fetchInfo, this));

Looking at the documentation of $.ajax(), I found that the context gets set to callbackContext variable. This gets with use success, error, beforeSend, complete, but not with data option.
AJAX options gets assigned to a variable named s:
s = jQuery.ajaxSetup({}, options),
The data option gets converted to string, but callBackContext is not used.
// Convert data if not already a string
if (s.data && s.processData && typeof s.data !== "string") {
s.data = jQuery.param(s.data, s.traditional);
}
So it is necessary to set specify the element for data using a variable other than this.

Related

Does calling jQuery's ajaxSetup with no parameters have any side effects?

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.

Javascript parameter dynamically change using Play

I have a javascript request like this to pass data to play framework and based on the different propertyKey, the event should have different parameter.
I do something like this.
The js is used by multiple windows. So this._propertyKey will change based on different windows.
_postEvent: function(customData) {
var propertyKey = this._propertyKey;
var Event = {
propertyKey : customData
},
url = play.url({
alias: 'controllers.eventController.trackEvent',
args: Event,
withCsrf: true
});
return $.ajax(url, {
type: 'POST'
});
},
The problem when I trigger this code. According to the request it sends, it is always Event.propertyKey instead of the customized propertyKey I pass in. For example, if for this window, propertyKey = 'region'. I want 'region' to pass in as the parameter. But no matter what propertyKey is, the post request always sends Event.propertyKey = XXX instead of Event.region = XXX.
Is there a way to pass in the propertyKey here Is use to make it change dynamically based on different pages?
When a function is called as a method of an object, its this is set to the object the method is called on. MDN Reference
To fix that part of the code, use window instead of this.
In order to set a property name to be the value of another variable, you have to create the object first, and then set the key/value pair using []. SO Reference
var Event = {};
Event[propertyKey] = customData;
var url = play.url({
alias: 'controllers.eventController.trackEvent',
args: Event,
withCsrf: true
});

How to pass an element to jQuery post inside a loop

I have the following code:
for (_field in _fields) {
$.post(
'/api/fields',
{ id: _field.id },
function(data, _field) {
alert(data);
} (data, _fields[_field)
);
}
I have to pass the _fields[_field] element to the function that returns the data from the jQuery because loses the reference to the right object during the loop. The problem is that in defining that the post function should have a _field parameter, you also have to specify a parameter for data, or data will be overwritten with _field.
Currently data returns as undefined because I have no data object defined inside the loop. I also tried passing in null, but that also just returns null. I'm looking for a way to pass the element without overwriting the data returned from the post function.
Is there any way to fix this, or is there perhaps an alternative jQuery method that can do what's needed?
You want a function factory function — a function that creates a function:
for (_fieldName in _fields) {
$.post('/api/fields',
{
// Unrelated, but I think this bit is wrong; shouldn't it be
// `id: _fields[_fieldName].id` ? You're trying to use `.id` on
// a string -- see below for a full update
id: _fieldName.id
},
makeHandler(_fields[_fieldName])
);
}
function makeHandler(field) {
return function(data) {
// Use `data` and `field` here
};
}
Note that in the object initializer we're passing into $.post, we're calling makeHandler to it runs and returns the function we'll then pass into $.post. That function is then called when the $.post completes, and has access to the data argument that $.post gives it as well as the field argument to makeHandler, because it's a closure over the context of the call to makeHandler, which includes the field argument. More: Closures are not complicated
Note that in the code above, I changed your variable _field to _fieldName to be more clear: The variable in for..in loops is a string, the name of a property. See also the comment, I think you were trying to use .id in the wrong place. Here's what I think you really wanted:
for (_fieldName in _fields) {
_field = _fields[_fieldName];
$.post('/api/fields',
{
id: _field.id
},
makeHandler(_field)
);
}
function makeHandler(field) {
return function(data) {
// Use `data` and `field` here
};
}
Also note that if _fields is an array, you shouldn't use for..in on it without safeguards. More: Myths and realities of for..in

JS Prototype scope with this/bind

I have the following code that creates an object in JavaScript. It uses prototype to define functions and constructors.
function objectClass(){
this.variables = new Array();
}
objectClass.prototype =
{
contructor: objectClass,
setInfo: function(){
$.ajax({
url: "info.json",
success: function(){
//for each json element returned...
this.variables.push(json[i]);
}
});
}
getInfo: function(){
return this.variables;
},
}
This is a similar example of what I am trying to do. I need to be able to return the array of variables when I call obj.getInfo(). It always throws an error. I believe it is because the "this" is referring to the scope of the ajax success function.
Any ideas on how to get it to reference the objects variable?
That's correct, the this value is not automatically passed and thus not set to the instance. To force this, you can use the context property that $.ajax accepts:
$.ajax({
context: this, // `this` is the instance here
This sets the this value inside the success callback to the one you specified.

jQuery passing parameters into .ajax()

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/

Categories

Resources