jQuery $.post() not working in Internet Explorer - javascript

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');

Related

Overriding Core Drupal JS Function To Remove Behavior, Should I Edit Property, Or Leave Override Function Empty?

We have a use case where we need to block Drupal's core ajax error handling from alerting users (we're handling the error reporting on our own). Previously another developer had commented out a line in the core ajax.js file, to prevent Drupal from spawning the alert box, but I'd like to handle it without touching core.
From the core, drupal.js:
/**
* Displays a JavaScript error from an Ajax response when appropriate to do so.
*/
Drupal.displayAjaxError = function (message) {
// Skip displaying the message if the user deliberately aborted (for example,
// by reloading the page or navigating to a different page) while the Ajax
// request was still ongoing. See, for example, the discussion at
// http://stackoverflow.com/questions/699941/handle-ajax-error-when-a-user-
// clicks-refresh.
if (!Drupal.beforeUnloadCalled) {
alert(message);
}
};
My current fix, is to override the Drupal.displayAjaxError function and change the Drupal.beforeUnloadCalled property that determines whether or not to alert the error:
var ajax_error_backup = Drupal.displayAjaxError;
Drupal.displayAjaxError = function (message) {
Drupal.beforeUnloadCalled = true;
ajax_error_backup(message);
};
My question, is whether or not this is an appropriate fix? I know that I could also override the function and just leave it empty - costing fewer lines, and not invoking another call to the original function (and saving the object I've created by backing up the original in ajax_error_backup).
Am I adding complexity to keep things tidy, or should I just override with:
Drupal.displayAjaxError = function (message) {
//empty
};
To clarify - the desire is to never have this ajax alert occur, so there's not functional difference between my desire to keep things neat/tidy, and just overriding the function with a blank one - there isn't a case where want this alert to succeed.
Thanks in advance for helping this old dog think through something with fresh eyes.
In this case, there isn't one option that seems to be clearly better than the other. It should be handled on a case by case basis, and in this case, either of the methods really is adequate.
I personally opted for using the slightly more expensive method of overriding the function and calling it back, because I felt that it might be somewhat more future-proof:
var ajax_error_backup = Drupal.displayAjaxError;
Drupal.displayAjaxError = function (message) {
Drupal.beforeUnloadCalled = true;
ajax_error_backup(message);
};
If Drupal were to extend the function on their end in the future, there might be another condition that we wouldn't want to override.
Overriding with the empty function would be the cheapest, but would also potentially be a bit heavy handed.
It seems that either approach is valid, and is probably best handled case-by-case.

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.

Getting History.js to work with Ajax-Solr

I'm working with Solr 4.3.0 and implementing Ajax-Solr for the interface. However, Ajax-Solr does not save state automatically. There is a ParameterStore and ParameterHashStore method but they don't work with legacy browsers. I used my google-fu and found the following but it doesn't work as intended:
https://github.com/evolvingweb/ajax-solr/pull/23
...with a few more resources I came up with this:
<script>
var Manager;
(function ($) {
Manager.setStore(new AjaxSolr.ParameterHashStore());
Manager.store.exposed = [ 'fq', 'q', 'start' ];
Manager.init();
// Establish Variables
var History = window.History; // Note: We are using a capital H instead of a lower h
if ( !History.enabled ) {
// History.js is disabled for this browser.
// This is because we can optionally choose to support HTML4 browsers or not.
return false;
}
State = History.getState(),
// Bind to State Change
History.Adapter.bind(window,'statechange',function(){ // Note: We are using
statechange instead of popstate
// Log the State
var State = History.getState(); // Note: We are using History.getState() instead
of event.state
History.log('statechange:', State.data, State.title, State.url);
});
// Log Initial State
History.log('initial:', State.data, State.title, State.url);
})(jQuery);
</script>
But it doesn't work. The Forward and Back buttons are broken in all browsers and nothing gets logged to the console.
What am I missing or is v4.3.0 inherently borked right now and needs a patch?
Would greatly appreciate any help. Thank you!
I know nothing about AJAX-Solr. But I think discussing some few things with you might help.
If AJAX-Solr works the same way the normal AJAX do, then AJAX-Solr will execute some server-side function and outputs it in client-side (of course without refreshing the actual page). As consequence, you should put the function triggering the ajax call inside your History.Adapter.bind(window,'statechange',function().
About State = History.getState(); it is responsible of returning the state data of a pushed state in history stack (url, title, ajax parameters). please to read the doc about hisrory.js on github. Note also that you are using a comma instead of semicolon in your code. In addition, you are calling this function twice. Call it only one time inside your Bind function to get the state parameters and use them in your ajax call (in order to refresh the part of your page while navigating over brower back-forward buttons).
I advise you to read also Back-Forward buttons of browser are showing weird behaviour. History.js, maybe it will help you understand positionning of ajax regarding Bind.
Good luck.

jQuery unload(): Syntax error after updating a Cookie - how to find the cause?

Solution below: Edit #2
I've a HTML-list the user is able to sort. I don't want to save the data after every drag/drop action, so I save the data on unload: in a cookie and database. Thats working, but:
After saving the data the list is hidden and I get a "syntax error" in this line:
<!DOCTYPE html>
It's strange because everything works fine after refreshing the same page (F5) without changing anything.
I try to find the cause but no success. That's the flow:
1. visit the page (index.php)
2. change the list (set: list_is_dirty = true)
3. click any internal link (call $(window).unload( ... save_data() ... )
4. target page appears without the list (syntax error!)
5. refreshing the page (everything works fine)
Do you have any idea how to find this error? Any tools or strategies? Or maybe the same experience with the unload function?
Thanks in advance!
Edit:
Some code:
var list_is_dirty = false;
// document ready?
$(function() {
function sort_list() {
// some code, not important
}
sort_list();
$(window).unload(function() {
if (list_is_dirty == true) {
/* ---------- HERE's the error! ---------- */
/* The error occures when I try to call the script.php
I tried load(), $.post(), $.get() but nothing works.
The string is correct. I'm not even able to call any of
these functions without params.
*/
// send data to script.php to save data
$("#div").load("script.php?str="+list_data_str);
$.cookie("list_data", list_data_str);
}
});
}
Edit #2 / Solution:
I don't know why, but everything works with window.onbeforeunload instead of jQuery.unload(). An explaination would be great! I'm sorry for this confusing thread!
window.onbeforeunload = function(e) {
$("#div").load("script.php");
}
I think that your issue is with: list_data_str as it's not defined anywhere.
if you are trying to say that you want to do AJAX post for example, then obviously you need to look for success event
else it appears that what your demo code is missing something because you can do it the way you are trying if at the receiving script you use $_GET over the URL and not pay attention to any parameters.. In other words, you are missing the object and when you refresh the page it's loaded into the DOM. Apparently that could be the issue that you are describing, I would suggest that you post a bit more of relevant to your issue code.. like the receiving script or any errors from a debugger like Firebug.
Regarding how to test it, you might want to use console.log in supported browsers or simply alert when is setting up the cookie.
var global list_is_dirty = false;
function sort_list(list, list_is_dirty) {
// some code, not important
//check the list and the flag
//you should return a value, else it does not make sense to use a function here.. note the var defined as global
return list; //?? not sure what to return as don't know what this code does from the posting
}
jQuery(function($)
{
$(window).load(function(e){
var list_data_str= sort_list( );
// send data to script.php to save data
e("#div").load('script.php?str='+list_data_str);
//on unload destroy the cookie perhaps?? or if it's not set a session variable
e.cookie("list_data", list_data_str);
...
The unload event
$(window).unload(function(e) {
$("#div").load("script.php?str="+list_data_str);
$.cookie("list_data", list_data_str);
}
});
}
....
// About your EDIT: Are you passing in here any parameters to the script? Because I think the problem is at that logic.
window.onbeforeunload = function(e) {
$("#div").load("script.php");

Retrieving jQuery.data() values from within setInterval

I've been stuck on this problem for a while now. I'm using jQuery's .data() method to store state in a plugin I'm writing. Everything works fine, except for when I try to retrieve these data values from within a setInterval block. I am able to see the jQuery object inside the setInterval block, but I'm not able to see values stored by the data() method.
tminusStart: function() {
return this.each(function() {
var $tminus = $(this).data("tminus.state", "running");
var intervalId = setInterval(function(tm) {
if ($tminus.tminusIsRunning()) {
$tminus.tminusDecrementCounter();
$tminus.data("tminus.settings").tick_event();
if ($tminus.tminusTimeRemaining() <= 0) {
$tminus.data("tminus.settings").expiration_event();
}
$tminus.text(tminus.tminusTimeRemaining);
}
else {
clearInterval(intervalId);
}
}, 1000, $tminus);
});
}
In the above code, the $tminus does return the jQuery object alright, but the calls to the functions - which are calling the .data() method - return undefined; so does the .data("tminus.settings") call.
Any help in understanding why .data() isn't working here would be greatly appreciated.
Rewrite of function removing cruft:
tminusStart: function() {
var tminus = this;
tminus.data("tminus.state", "running");
return this.each(function() {
console.log(tminus.data("tminus.state")); // "running"
var intervalId = setInterval(function() {
console.log(tminus.data("tminus.state")); // undefined
}, 1000);
});
}
I need to know why it's undefined in the setInterval block
What are tminusIsRunning and tminusDecrementCounter? Did you mean to call that under $tminus? Unless you're extending jQuery, those calls are going to error out. If you're using Chrome, check the Javascript Console, you should see something like: "Uncaught TypeError: Object [object Object] has no method 'tminusIsRunning'"
.data() doesn't work with xhtml + IE (see note in docs).
Alternatively, This looks like a jQ extension, so watch out for that. jQuery has a (IMO) bad habit of aliasing this all over the place. Make sure you don't have a dependency on this being something different than what it is. I suggest installing firebug and using console.log to log this in both the place where you set the value, and where you access it. If it's not the IE issue, I suspect this would locate it.
Finally figured it out. I'm using jasmine to test drive this and the jasmine-jquery library has a fixtures piece which I'm apparently not using correctly. I tested the code in a webpage and everything is now working according to plan. Now I just have to make sure all my tests are passing.
I won't accept my own answer since I didn't provide the necessary information to begin with. I appreciate everyone's time on this. I really wish I could have accepted someone's answer.

Categories