jQuery injecting data in ajax global event - javascript

I'm trying to inject data in my ajax requests, but it fails and I don't know why. I tried to look at the jQuery source code, but still can't find why it doesn't work, Any help appreciated. Here is the code :
$('#someElement').ajaxSend(function(e, req, options) {
options.data += (options.data.length > 0 ? '&' : '') + '__token=' + $('input#requestToken').val();
}).ajaxSuccess(function(e, req, options, data) {
if (data.nextToken) {
$('input#requestToken').val(data.nextToken);
delete data.nextToken;
}
});
The response looks like this :
{
"response":
{
"code":0,
// ...
},
"nextToken":"4ded26352b3d44"
}
A typical request would be, for example :
$.getJSON(url, {something:'value'}, function(data) {
if (data.response.code != 0) {
// handle code
}
});
The problem is that, the data sent is "something=value"; the modified data is not sent.
** EDIT **
The current request data is
something: value
and should be
something: value
__token: 4ded288eec1f56
In the ajaxSend event callback, if I print the value of options.data after modifying it, the value is "something=value&__token=4ded288eec1f56", but "__token=4ded288eec1f56" is not sent. Why isn't it sent in the request?
But more specifically, how to "fix" this, if even possible?

I think the problem is that by the time jQuery decides to call the "ajaxSend" callback, the parameters have already been used to prepare the request. Thus, changing them in that handler has no effect.
edit — given the answer from #mikermcneil I'm not sure this is right. The jQuery "ajax" method is, to say the least, complicated. His sample page certainly seems to work, which confuses me but probably should just help me realize how little I know about jQuery internals :-)

-edit
Update-- the trouble is with getJSON.
It looks like, while jQuery does fire the ajaxSend event in both cases, it doesn't actually use the changed data variable with getJSON like it does with post.
Replace getJSON with $.post to solve your problem (that's what I'm doing in the example I linked to below).
-edit-
Well, I set up a version of it here:
http://abolition.me/toys/View/attachAjax.html
(see the console)
I'm having the server send back whatever it got and it's saying:
__token: "toketoketoke"
key: "val1"
key2: "val2"
So it looks like modifying the request data is working-- what does your handler look like server-side?
I'm looking into it-- first and foremost though (and I mistake I made as I tried to replicate the problem), have you checked that you're assigning your event after the document is ready? ($(function(){ });)

I am not sure that your JSON response is correct:
{
"response":
{
"code":0, <-- this is not valid
},
"nextToken":"4ded26352b3d44"
}
valid should be:
{
"response":
{
"code":0
},
"nextToken":"4ded26352b3d44"
}
To validate your JSON response you can use:
The JSON Validator

You are only passing data within the second parameter in your getJSON call {something:'value'}. Any data you want to send to the server must be included there. Thus, the __token must be included in that parameter.
The third parameter in the getJSON call is the call back function. The parameter passed to that function is the response from the server.
$.getJSON(
url,
{
something:'value',
__token: 'token value'
,
function(response) {
if (response.response.code != 0) {
// handle code
}
}
);

Related

What's the correct way to send Javascript code along with rendered HTTP to a client?

Mid development I decided to switch to server-side rendering for a better control amongst other benefits. My web application is completely AJAX based, no url redirecting, so the idea here is a website that builds itself up
I just couldn't figure out the proper way to send javascript events/functions along with the html string, or should all the necessary javascript always be preloaded in the static files?
Let's say client clicks a pre-rendered button 'open table'
The server will make a query, build the html table and send it back, but this table also needs javascript triggers and functions to work properly, how are these sent, received and executed?
There are a couple of articles that mention to not use eval() in Javascript, is there any way around this? I don't want to have to preload unnecessary events for elements that don't yet exist
The server is Python and the Client is Javascript/JQuery
Theoretical example :
Client Base Javascript :
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
eval(response.javascript()); //??
}
});
Python Server(views.py) :
def get_table(request):
data = {}
#String containing rendered html
data['html'] = get_render_table()
#String containing Javascript code?
data['javascript'] = TABLE_EVENTS_JAVASCRIPT
return HttpResponse(json.dumps(data),content_type='json')
Worth noting my question comes from an experimental/learning perspective
Update:
You can use jQuery.getScript() to lazy load JS. I think this solution is as close as you can get to run JS without using eval().
See this example:
jQuery.getScript("/path/to/script.js", function(data, textStatus, jqxhr) {
/* Code has been loaded and executed. */
console.log( data ); // Data returned
console.log( textStatus ); // Success
console.log( jqxhr.status ); // 200
console.log( "Load was performed." );
});
and "/path/to/script.js" could be a string returned from $.getJOSN response.
Also, the documentation for getScrippt() has examples on how to handle errors and cache files.
Old Answer:
Using .on() attaches events to current and future DOM elements.
You can either attache events prior to DOM insertion or attache event after DOM insertion.
So in your example you can do something like:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
var code = $(response.html);
code.find(".elementToFind").on("click", function (){
// Code to be executed on click event
});
$("#table_div").append(code);
}
});
I did not test the code but I think it should work.
Assuming you can't just set up an event-binding function and then call it from the main script (the JavaScript you need can't be guessed ahead of time, for example) then one really easy way is just to append the JavaScript to the bottom of the returned HTML content within script tags. When it's appended along with the HTML, the script should simply execute, with no eval() required.
I can't swear that this would work in old browsers, but it's a trick I've used a couple of times, and I've had no problems with it in Firefox, Chrome, or any of the later IE versions.
I think I see what you're asking here, from my understanding you want to send the new "page" asynchorously, and render the new javascript and html. It looks like you already got your request/response down, so i'm not gonna go and talk about sending JSON objects, and the whole "how-to" of sending html and javascript because it looks like you got that part. To do what you want and to dynamically add your javascript in, this stackoverflow question looks like it has what you need
Is there a way to create a function from a string with javascript?
So pertaining to your example, here is how it would look when you recieve the JSON string from your python script:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
/* Create function from string */
var newFunction = Function(response.javascript['param_1'], response.javascript['param_2'], response.javascript['function']);
/* Execute our new function to test it */
newFunction();
}
});
*Your actual function contents would be the string: response.javascript['function']
*Your parameter names if any would be in separate strings ex: response.javascript['param_1']
That is almost a direct copy of the "String to function" code that you can see in the linked question, just replaced it with your relevant code. This code is also assuming that your object is sent with the response.javascript object containing an array with your actual function content and parameter names. I'm sure you could change the actual name of the var too, or maybe put it in an associative array or something that you can keep track of and rename. All just suggestions, but hopefully this works for you, and helps you with your problem.
I am also doing similar work in my project where I had to load partial html using ajax calls and then this partial HTML has elements which requires events to be attached. So my solution is to create a common method to make ajax calls and keep a js method name to be executed post ajax call in html response itself. For example my server returns below html
<input type="hidden" data-act="onPartialLoad" value="createTableEvents" />
<div>.........rest of html response.....<div>
Now in common method, look for input[type='hidden'][data-act='onPartialLoad'] and for each run the method name provided in value attribute (value="createTableEvents")
Dont Use Eval() method as it is not recommended due to security
issues. Check here.
you can run js method using window["method name"]...so here is a part of code that I use.
$.ajax(options).done(function (data) {
var $target = $("#table_div");
$target.fadeOut(function () {
$target.html(data);
$target.fadeIn(function () {
try {
$('input[data-act="onPartialLoad"]', $target).each(function () {
try {
//you can pass parameters in json format from server to be passed into your js method
var params = $(this).attr('params');
if (params == undefined) {
window[$(this).val()]();
}
else {
window[$(this).val()]($.parseJSON(htmlutil.htmlDecode(params)));
}
} catch (e) {
if (console && console.log) {
console.log(e.stack);
console.log($(this).val());
}
}
});
}
catch (e) {
console.log(e.stack);
}
});
});
});
use jQuery.getScript() (as suggested by Kalimah Apps) to load the required js files first.

Jquery global ajax event handler w/ json data

I'm trying to make global ajax handler of general purpose responses. (Eg. refresh page)
Is there any handler or hack so i'd get already parsed json, so i woudn't have to parse it twice?
$(document).ajaxSuccess(function(e, xhr) {
// Validate and parse xhr.responseText TWICE!
});
Okay, found a bit "hacky" solution, maybe useful to others :)
Solution is to override jquery ajax json parser:
function parseJsonResponse(d) {
var json = jQuery.parseJSON(d); // Same as default
// Do anything with json object :)
return json;
}
// Override original parser, defaults to jQuery.parseJSON.
jQuery.ajaxSettings.converters['text json'] = parseJsonResponse;
And if you dont want parseJsonResponse to be a global function then you can put this code in self-executing anonymous function

Log upon AJAX call or URL change

Can I add javascript code that logs every time the user is executing an AJAX call or changing the URL(exiting my page)
I want this piece of code to identify the ajax call automatically, I don't want to do it manually wherever there is an ajax call
if you are willing to use jQuery than try this one:
create a common function for all ajax requests
function ajxCall(url,data,method)
{
$('#logDiv').html(url+'<br>'); // Placing all request URLs in a debug div
$.ajax({url : url,
method : method ,
data : data , // data will be a jason object or you can set it by changing dataType
dataType:'JSON'})
}
function someEvent() // assign this handler to your event
{
ajaxCall('http::localhost/login.php',
{username:'my_user',password:my_password,
'POST'});
}
You can also create it with out jQuery. I have just described the idea. Hope It helps :) regards.

jQuery $.post() not working in Internet Explorer

I have the following snippet of jQuery:
var AlertType =
{
Save: function () {
var model = $('#alert').serialize();
$.post('/account/alert/edit', model);
}
}
When AlertType.Save() is called, the $.post() does not work in IE, but in all other browsers (surprising right?) I have tried to research the problem, but it is a fairly broad category or problems. I have even placed a callback function in the $.post() and tried to alert() inside of the callback, but it never hit the alert.
What might be causing this, and what would the fix be?
In your shoes I would break the problem down to its smallest chunk and then build up from there.
Step 1
Are you sure AlertType.Save() is being called at all? Put an alert in:
var AlertType =
{
Save: function () {
alert('Save called.');
var model = $('#alert').serialize();
$.post('/account/alert/edit', model);
}
}
Step 2
If Save() is being called, try calling $.post() with null instead of model. Put a breakpoint in the code for the action method for Edit in the Alert controller. You want to make sure that the controller code is being called.
Step 3
If the controller code is being called, then you have a problem with model. (Not sure where to take it from there, sorry). If the controller code is still not being called, then try calling $.post() directly i.e. without using AlertType.Save(). So instead of:
AlertType.Save();
do the actual $.post(). You want to eliminate the chance of it being the javascript object at fault here.
Perhaps the above is overkill, but you only have to do this once and you will have learnt something if it ever happens again :) From experience IE can make you have to go around the houses in order to diagnose a problem, since IE does stupid things under the hood sometimes, that other browsers just don't do. Gotta love IE.
IE caches more aggressively than other browsers in my experience.
Try adding a random number to the query:
$.post('/account/alert/edit?r=' + (Math.random() * 999), model);
It could be security policies on the browser. Is IE blocking the use of XmlHttpRequest, possibly for all but a handful of trusted domains?
Try the $.ajax object, it work fine in IE 8 :
var ajaxobject = $.ajax(
{
type:'POST',
url:'/account/alert/edit',
cache:false,
async:true,
global:false,
dataType:"html",
data:"model=" + $('#alert').serialize(),
timeout:10000,
success:function(recept)
{
alert('sucess !\nReceived data :\n' + recept);
},
error:function()
{
alert('failed.');
}
});
if(ajaxobject == undefined)
alert('Ajax object creation failed');

Conditional call based on JSON data

I am trying to modify my Javascript page, which uses Ext Js library.(I don't have any idea about ext js, haven't worked on it either)
What I want To do is that based on the JSON DATA particularly the field "successProperty", I want to decide whether to upload the grid or give an alert.
What I can possibly do is to add an event to the class. but i don't Know how to do it.
Can someone give me a nice example which can help me out in achieving what i need .
Thanks.
please let me know if I need to give any more details
thanks again..
The 'successProperty' is not what you think. That property is used internally by ExtJS to know how to find out if the method had an error. Its a string containing the "name" of the property inside the returned JSON which will tell the ExtJS framework that something went wrong, and not the error status itself. So, that is why ExtJS let you "define" that property. And as your server side will be defined by you, you can choose any name you like for your success status, and if you choose something different than success (which is the default successProperty) then you define it in the successProperty configuration property of the JsonReader.
And the easy way to detect if an error happened when you load a grid is checking the 3rd parameter (called success) of the callback in the load method:
store.load({
params:{start:0, limit:15},
callback: function(result, options, success) {
if (!success) {
alert('error!!');
}
}
});
There are more generic ways of handling server side errors, instead of defining a callback on every store.load you can use:
// Listen to "exception" event fired by all proxies
Ext.data.DataProxy.on('exception', function(proxy, type, action, ex) {
alert('Error through DataProxy.exception at ' + type + '.'+ action);
});
Or if were already using Ext.Direct you could use its exception event (probably you are not using Ext.Direct, so don't expect it just work by itself):
Ext.Direct.on('exception', function(ex) { alert(ex.message); });
I put together a complete example with the first 2 ways of catching errors: http://jsfiddle.net/vZGvM/.
The example has no errors but you can simulate an error by pointing the url of the ScriptTagProxy to any invalid url (it will take a time to respond if you do that, but you will see both alerts).

Categories