I'm using the .load() method in jQuery but I've realized that the request to my server should use ISO-8859-1 charset and not UTF-8. The problem is that I can't find how to set load method to use a different encoding. I read that .ajax method has 'content-type' setting to do this, but what about load method? I find load very useful when I need to update data from some divs without refreshing the page.
Any help would be appreciated, thanks.
Using ajaxSetup allows you to specify the settings for new ajax calls.
All subsequent Ajax calls using any function will use the new
settings, unless overridden by the individual calls, until the next
invocation of $.ajaxSetup().
with beforeSend you can provide a callback function to modify the XMLHttpRequest object before it's going to be send. jQuery Reference
Mozilla provides documentation about overrideMimeType():
Overrides the MIME type returned by the server. This may be used, for
example, to force a stream to be treated and parsed as text/xml, even
if the server does not report it as such.This method must be called
before send().
Borrowing code from this answer you could do:
$.ajaxSetup({
'beforeSend' : function(xhr) {
xhr.overrideMimeType('text/html; charset=ISO-8859-1');
},
});
//$('body').append('<div id=qqq>dfsdfsdf</div>')
//$('#qqq').load2('/index.php?showtopic=925 #post-29397','','','text/html; charset=utf-8')
//$('#qqq').load2('/index.php?showtopic=925 #post-29397','','','text/plain; charset=windows-1251')
//
jQuery.fn.load2 = function( url, params, callback, overrideMimeTypeVar) {
if ( typeof url !== "string" && _load ) {
return _load.apply( this, arguments );
}
var selector, type, response,
self = this,
off = url.indexOf(" ");
if ( off >= 0 ) {
selector = jQuery.trim( url.slice( off ) );
url = url.slice( 0, off );
}
// If it's a function
if ( jQuery.isFunction( params ) ) {
// We assume that it's the callback
callback = params;
params = undefined;
// Otherwise, build a param string
} else if ( params && typeof params === "object" ) {
type = "POST";
}
// If we have elements to modify, make the request
if ( self.length > 0 ) {
jQuery.ajax({
url: url,
// if "type" variable is undefined, then "GET" method will be used
type: type,
dataType: "html",
data: params,
// ++++++++++++++++++++++++++++++++++++++++++++++++++
beforeSend: function(x) {
if(x && x.overrideMimeType && overrideMimeTypeVar!=''){
x.overrideMimeType(overrideMimeTypeVar);
}}
// +++++++++++++++++++++++++++++++++++++++++++++++++++
}).done(function( responseText ) {
// Save response for use in complete callback
response = arguments;
self.html( selector ?
// If a selector was specified, locate the right elements in a dummy div
// Exclude scripts to avoid IE 'Permission Denied' errors
jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
// Otherwise use the full result
responseText );
}).complete( callback && function( jqXHR, status ) {
self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
});
}
return this;
};
Related
I get some scripts asynchronously on my login page:
$.when(
$.getScript("/Scripts/View/scroll-sneak.js"),
$.getScript("/Scripts/kendo/kendo.custom.min.js"),
$.Deferred(function (deferred) {
$(deferred.resolve);
})
).done(function (res1, res2) {
if (res1[1] == "success") {
}
if (res2[1] == "success") {
}
alert('all script loaded...');
});
I have two queries here:
How can I leverage browser cache here, as getScript always take fresh script.
How can I have promise that this script will be available to all pages on same domain.
Alternate solutions are welcome.
Answer to your first question is set cache true. Jquery documentation page also mentions a way
jQuery.cachedScript = function( url, options ) {
// Allow user to set any option except for dataType, cache, and url
options = $.extend( options || {}, {
dataType: "script",
cache: true,
url: url
});
// Use $.ajax() since it is more flexible than $.getScript
// Return the jqXHR object so we can chain callbacks
return jQuery.ajax( options );
};
// Usage
$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
console.log( textStatus );
});
For your second question: Please clarify more, what you want to achive?
I want to build up an flexible small API to backend for the client. To provide some convenience in using default success-/error- handlers or writing own ones, I planned to support the user with the option to pass both handlers one or none. I tried as follows.
Snippet of file "API" to backend:
function someRPCcall(method, url, data, successHandler, failedHandler) {
// checking if successHandler and failedHandler are defined and passed functions
if (paramType1 === 'undefined' || paramType1 === 'null') {
successHandlerHelper = defaultSuccessRESTHandler;
} else if (paramType1 === 'function') {
successHandlerHelper = successHandler;
}
if (paramType2 === 'undefined' || paramType2 === 'null') {
failedHandlerHelper = defaultFailedRESTHandler;
} else if (paramType2 === 'function') {
failedHandlerHelper = failedHandler;
}
ajaxCall(method, url, data, successHandlerHelper, failedHandlerHelper);
}
function ajaxCall(method, url, data, success, failed) {
console.log("in ajaxCcall");
$.ajax({
type: method,
contentType: "application/json",
data: data,
url: url,
success: success,
error: failed
dataType: "json"
});
console.log("ajaxCall - call done");
}
Snippet of file of client code
someRPCcall will be indirectly called by functions in another file:
someFunctionRPCcall("bla", null, errorHandler);
whereas searchWordOccurrenceRPCcall is calling someRPCcall
Above the failureHandler would be a selfdefined Handler, but following calls also should be possible:
someFunctionRPCcall("bla", null, successHandler, errorHandler);
someFunctionRPCcall("bla", null, successHandler);
someFunctionRPCcall("bla", null);
I heard about taking an object, in which the functions would be defined....
This code does not call the self defined handlers, but I guess this is another problem (using apply is missing or something like that)
The question I wanted to put here is:
Is there a way to pass both functions as optional parameters? How about that proposal useing objects?
Thanks
As you mentioned, you can get your function to take an object, eg:
function someRPCcall(args) {
var method = args.method || "POST";
var url = args.url || "default";
var data = args.data || {};
var successHandler = args.success || defaultSuccessRESTHandler;
var failedHandler = args.failed || defaultFailedRESTHandler;
ajaxCall(method, url, data, successHandler, failedHandler);
}
You will notice above that if a property is not present on the args object then it is given a default.
Then call it as follows:
someRPCcall({
url : "the url",
failed: function() { ... }
});
Of course, you could throw an exception if some values are not set, eg url:
function someRPCcall(args) {
if(!args.url) {
throw "url must be set";
}
}
im trying to create own POST request. Here is my function:
function sendPost(o) {
var h = new XMLHttpRequest();
h.onreadystatechange = requestComplete;
function requestComplete() {
if ( h.readyState === 4 ) {
if ( h.status === 200 ) {
if ( o.done ) {
o.done(h.responseText);
}
} else {
if ( o.fail ) {
o.fail(h.responseText);
}
}
}
}
h.open('POST', o.url, true);
h.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
h.send(o.data);
}
Everything is OK, but im confused, how to set its dataType to script, like in jQuery:
$.ajax({
url: 'someurl.php',
type: 'POST',
dataType: 'script' // <-- how to do this?
});
dataType has very little to do with sending Ajax requests. It is primarily about what jQuery does with the response.
From the documentation:
"script": Evaluates the response as JavaScript and returns it as plain text. Disables caching by appending a query string parameter, "_=[TIMESTAMP]", to the URL unless the cache option is set to true.
So there is some modification to do with sending here.
Take o.data
Get a timestamp from a new Date()
Check (by looking at indexOf('?') if it has a query string already
Append either ? or & to the URL followed by the time stamp
The rest is all about processing the response:
Evaluates the response as JavaScript
So:
eval(h.responseText);
This is all rather nasty though. Generally speaking, if you want to dynamically load a script, you are usually better off doing it by adding a <script> element to a page.
I'm recently fooling around with some ajax polling techniques. However, it seems like I can't overwrite the onreadystatechange handler from a XMLHttpRequest object in FireFox (3.6.7).
On tracking the problem why FF throws an exception when trying to access onreadystatechange, I realized it depends whether the send() method was called or not.
In other words, here is an example (plain js, no jQuery so far), that works:
(This is fairly simplified just for a demonstration)
var myxhr = new XMLHttpRequest();
myxhr.open("GET", "/my/index.php");
myxhr.onreadystatechange = function(){
console.log('ready state changed');
};
console.log("onreadystatechange function: ", myxhr.onreadystatechange);
myxhr.send(null);
This works, better said it's possible to access myxhr.onreadystatechange here. If I switch the last two lines of code, FF throws an exception, basically telling me that I'm not allowed to access this object.
myxhr.send(null);
console.log("onreadystatechange function: ", myxhr.onreadystatechange);
Fails.
So where is my actual problem?
Well, I want to use jQuery's $.ajax(). But if I try to overwrite the onreadystatechange method of a XHR object that was returned from $.ajax(), I receive the same FireFox exception.
Ok I already found out why this happens, so I thought about, hey what about the beforeSend property of $.ajax() ? So I basically tried this:
var myxhr = $.ajax({
url: "/my/index.php",
type: "GET",
dataType: "text",
data: {
foo: "1"
},
beforeSend: function(xhr){
var readystatehook = xhr.onreadystatechange;
xhr.onreadystatechange = function(){
readystatehook.apply(this, []);
console.log('fired');
};
},
success: function(data){
console.log(data);
},
error: function(xhr, textStatus, error){
console.log(xhr.statusText, textStatus, error);
}
});
Guess what, FireFox throws an exception. So what do you do now? You digg into the jQuery source, like I did. But that brought more questions than answers actually. It looks like beforeSend() is really called before xhr.send() is executed. So I'm wondering why on earth FireFox does not allow to overwrite the handler at this point.
Conclusion?
It's impossible to create a custom readystatechange handler with jQuery/Firefox ?
I agree with Maz here, you can still benefit form the query handling and creating of the object, and also no need to patch jquery for this
however, if you dont mind patching jquery you could add these lines
// The readystate 2
} else if ( !requestDone && xhr && xhr.readyState === 2 && isTimeout !== 'timeout' && s.state2) {
s.state2.call( s.context, data, status, xhr );
// The readystate 3
} else if ( !requestDone && xhr && xhr.readyState === 3 && isTimeout !== 'timeout' && s.state3) {
s.state3.call( s.context, data, status, xhr );
before this line: (jQuery v 1.4.4) or just search for the readyState === 4 in the source
// The transfer is complete and the data is available, or the request timed out
} else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
now you can use the $.ajax again and put a handler up for state2 and state3 like so:
$.ajax({
url: 'http://www.stackoverflow.com',
cache: false,
success:function(){console.log('success');},
error: function (){console.log('error');},
complete: function (){console.log('complete');},
state2: function (context,data,status,xhr) {console.log('state2');},
state3: function (context,data,status,xhr) {console.log('state3');}
});
it doesnt exactly behave like the other handlers, eg returngin false wont do a thing
but you can still handle the xhr object and abort that way
ill see if i can submit this to be included in the source later this day, who knows they might accept it
If you want a large level of customization, you can just get the XMLHttpRequest object and control it yourself.
var x=new $.ajaxSettings.xhr();
x.onreadystatechange=function(){ ... }
...
You can do this by doing something like that:
$.ajax({
type: "POST",
url: "Test.ashx",
data: { "command": "test" },
contentType: "application/x-www-form-urlencoded; charset=utf-8",
dataType: "json",
beforeSend: function (request, settings) {
$(request).bind("readystatechange", function (e) { alert("changed " + e.target.readyState); });
}});
As a learning exercise I've hacked together a script for an SO feature request (for the purposes of this question please ignore the merits or otherwise of that request). In the script I've encountered a technical issue that my limited javascript knowledge can't get past and I'd appreciate suggestions on how to resolve it.
To avoid spamming the server I use some search hacks to determine the number of answers and accepted answers for a tag. This involves using window.setTimeout() to callback to a function that sends a get request for each tag, increasing the timeout on each call to stagger the requests.
To get the results in a single request involves appending &pagesize=1 to the end of the url in the get request, so that the number of pages in the results gives you the total number of results without having to make any further requests.
A side affect of this approach is that subsequent page views use &pagesize=1 and I only see a single entry. I attempt to resolve this by firing another query with &pagesize=30 to reset it afterwards, but as it is all asynchronous the timing of the last query can result in the pagesize either being 1 or 30, depending on which request completes first. I've tried adding a further timeout and callback for this "reset" query but it hasn't really helped.
Is there a means to monitor the queries, waiting until all have been completed, then once they have all completed send the reset request? Or is there another approach that I could take?
You could make a call chain
Based on my previous idea of a ParallelAjaxExecuter, here's a SerialAjaxExecuter
$(function(){
var se = new SerialAjaxExecuter( function( results )
{
console.log( results );
}, 1000 );
se.addRequest( $.get, 'test.php', {n:1}, function( d ){ console.log( '1 done', d ); }, 'text' );
se.addRequest( $.get, 'test.php', {n:2}, function( d ){ console.log( '2 done', d ); }, 'text' );
se.addRequest( $.get, 'test.php', {n:3}, function( d ){ console.log( '3 done', d ); }, 'text' );
se.addRequest( $.get, 'test.php', {n:4}, function( d ){ console.log( '4 done', d ); }, 'text' );
se.execute();
});
var SerialAjaxExecuter = function( onComplete, delay )
{
this.requests = [];
this.results = [];
this.delay = delay || 1;
this.onComplete = onComplete;
}
SerialAjaxExecuter.prototype.addRequest = function( method, url, data, callback, format )
{
var self = this;
this.requests.push( {
"method" : method
, "url" : url
, "data" : data
, "format" : format
, "callback" : callback
} );
var numRequests = this.requests.length;
if ( numRequests > 1 )
{
this.requests[numRequests-2].callback = function( nextRequest, completionCallback )
{
return function( data )
{
completionCallback( data );
setTimeout( function(){ self.execute( nextRequest ); }, self.delay );
}
}( this.requests[numRequests-1], this.requests[numRequests-2].callback )
}
}
SerialAjaxExecuter.prototype.execute = function( request )
{
var self = this;
if ( 'undefined' == typeof request )
{
request = this.requests[0];
var lastRequest = this.requests[this.requests.length-1];
lastRequest.callback = function( completionCallback )
{
return function( data )
{
completionCallback( data )
self.onComplete( self.results );
}
}( lastRequest.callback )
}
request.method( request.url, request.data, function( r )
{
return function( data )
{
self.results.push( data );
r.callback( data );
}
}( request ) )
}
I didn't bake in a sleep period between requests, but that could certainly be added. Added the timeout
Note: this example is littered with console.log() calls for which you need firebug, or just remove them.
I'm not sure if I fully understand the problem but why not chain the requests rather than using a setTimeout? So at the end of the response handler of one request fire off the next request.
Append &pagesize= to every link on page that would need it with the pagesize you're currently using.