In Microsoft Edge, a GET request is not running. I have stepped through the code to the point of the AJAX request being run, and set a breakpoint in the callback(s). However, the code never reaches the callbacks.
I already have a .then() and .fail() setup with callbacks, and tried adding a .done() and .always() with callbacks, but none of the code in the callbacks is running.
I then checked the network tab in dev-tools, and I cannot find the request at all. It seems as though Edge is not firing the request off for some reason.
request = function(options, resolveScope) {
var deferred = $.Deferred();
corsHandler.makeRequest(options)
.done(this._wrap(function(response) {
deferred.resolveWith(resolveScope, [response]); //never gets here
}, this))
.fail(this._wrap(function(response) {
deferred.rejectWith(resolveScope, [response]); //never gets here
}, this));
return deferred;
}
This is what calls the request function above.
ajaxFunc = function(data, scope) {
return request({
url: '/path/to/server',
internalUrl: true,
method: 'GET',
datatype: 'json',
data: data
}, scope);
}
This is the implementation used to make that request.
(function() {
// set data var
return ajaxFunc(data, self)
.then(function(res) { console.log(res); }) //never gets here
.done(function(res) { console.log(res); }) //never gets here
.fail(function(res) { console.log(res); }) //never gets here
.finally(function(res) { console.log(res); }) //never gets here
})();
Here is the cors stuff. (I don't know a whole lot about this.)
corsHandler.makeRequest = function(options) {
// resolve default options
_.defaults(options, {
xhr: null,
corsUrl: null,
url: null,
method: 'GET',
data: {},
success: function() {},
error: function() {},
terminate: false,
binary: false,
headers: {},
internalUrl: false,
datatype: ''
});
// if url is internal, create absolute url from relative url
if (options.internalUrl) {
options.url = this.createAbsoluteInternalUrl(options.url);
}
// resolve cors url or proxy url
options.corsUrl = options.corsUrl || this.getCorsUrl(options.url);
if (!options.corsUrl) {
options.url = this.getProxyUrl(options.url);
options.corsUrl = this.getCorsUrl(options.url);
}
// create xhr
if (!options.xhr && options.corsUrl) {
options.xhr = this.createXhr(options.corsUrl);
}
// create cleanup procedure
var cleanUpAfterRequest = $.proxy(function() {
if (options.terminate) {
options.xhr.destroy();
this._removeCacheXhr(options.corsUrl);
}
}, this);
// prepare deffered object
var deferred = $.Deferred();
deferred
.done(function() {
if (options.success) {
options.success.apply(null, Array.prototype.slice.call(arguments));
}
})
.fail(function() {
if (options.error) {
options.error.apply(null, Array.prototype.slice.call(arguments));
}
});
// make actual request
if (!options.xhr) {
throw 'corsHandler: xhr object was not created or defined to make request';
// this does not happen
}
options.xhr.request(
{
url: options.url,
method: options.method,
data: options.data,
binary: options.binary,
headers: options.headers,
datatype: options.datatype
},
function() {
deferred.resolve.apply(null, Array.prototype.slice.call(arguments));
cleanUpAfterRequest();
},
function() {
deferred.reject.apply(null, Array.prototype.slice.call(arguments));
cleanUpAfterRequest();
}
);
return deferred;
}
UPDATE
It looks like the issue is in easyXDM. waitForReady() is not firing on(window, "message", waitForReady) in edge. I'm looking into the issue more now.
easyXDM snippet:
targetOrigin = getLocation(config.remote);
if (config.isHost) {
// add the event handler for listening
var waitForReady = function(event){
if (event.data == config.channel + "-ready") {
// replace the eventlistener
callerWindow = ("postMessage" in frame.contentWindow) ? frame.contentWindow : frame.contentWindow.document;
un(window, "message", waitForReady);
on(window, "message", _window_onMessage);
setTimeout(function(){
pub.up.callback(true);
}, 0);
}
};
on(window, "message", waitForReady);
// set up the iframe
apply(config.props, {
src: appendQueryParameters(config.remote, {
xdm_e: getLocation(location.href),
xdm_c: config.channel,
xdm_p: 1 // 1 = PostMessage
}),
name: IFRAME_PREFIX + config.channel + "_provider"
});
frame = createFrame(config);
}
The above snippet runs, but the waitForReady method is never called. The only browser it's not called in is Edge (Works in IE8+, Chrome, Safari, FF, and mobile chrome/safari).
It turns out there was a required "hack" that a previous developer wrote into our implementation of easyXDM.
In our implementation of easyXDM, we had to update the Window object on IE because our app launches in an iFrame. As Edge isn't technically a version of IE, our test was failing, so the code was not running to update window to be window.parent in the context of easyXDM.
We are using typeof document.documentMode === 'number' to detect IE, but document.documentMode is undefined in Edge, so we added a navigator.userAgent check for Edge.
This resolved the issue.
Related
I am working on a phonegap app which uses Backbone JS.
During ajax calls the header contains:
"Origin":"file://"
Which is not supported by the server. I tried to set Origin header as null but in chrome it is not allowed.
Backbone.ajax = function() {
arguments[0].headers = {
'Accept': "application/json",
'Origin': "null"
};
return Backbone.$.ajax.apply(Backbone.$, arguments);
};
Which throws error:
Refused to set unsafe header "Origin"
Only work around I can think of to solve this issue is to use the cordovaHttp plugin. But I am unable to figure out how to override Backbone.ajax to use cordovHTTP.
Link to the cordova plugin:
https://github.com/silkimen/cordova-plugin-advanced-http
Although this is related to CORS, my question is specific to Overriding Backbone ajax method using the cordovaHttpPlugin
It works:
function isPhoneGap() {
return (window.cordova || window.PhoneGap || window.phonegap)
&& /^file:\/{3}[^\/]/i.test(window.location.href)
&& /ios|iphone|ipod|ipad|android/i.test(navigator.userAgent);
}
Backbone.sync = function( method, model, options ) {
if(method == "read"){
if(isPhoneGap()){
cordova.plugin.http.get(model.url, {}, { Origin: "null" }, function(response) {
// prints 200
console.log(response.status);
try {
options.success(JSON.parse(response.data));
} catch(e) {
console.error("JSON parsing error");
}
}, function(response) {
console.log(response.status);
console.log(response.error);
});
}else{
$.ajax({
type : 'GET',
url : model.url,
dataType : 'json',
success : function(data) {
console.log(data);
if(model instanceof Backbone.Collection){
model.reset(JSON.parse(JSON.stringify(data)));
}else{
model.set(JSON.parse(JSON.stringify(data)));
}
}
});
}
}
}
Problem: Extracting data from ajax request inside page.evaluate
Description: I usually get variables out of page.evaluate by simply returning them. However, I need to make an ajax request within the context of a page, and then I need to process its result out of the page's context.
The code I'm trying to fix is:
var theOutput = page.evaluate(function () {
return $.ajax({
async: false,
url: 'http://localhost:8080/captcha.php',
data: { filename: 'C:\\wamp\\www\\images\\0.png' },
type: 'post',
success: function (output) {
parsed_output = $.parseHTML(output);
return parsed_output[4].data.trim();
},
});
});
console.log(theOutput);
The variable parsed_output[4].data.trim() is a string. But when I log output I get a [object Object], with the properties abort, always, complete, done, error, fail, getAllResponseHeaders, getResponseHeader, overrideMimeType, pipe null, progress, promise, readyState, setRequestHeader, state, statusCode, success,then.
Question: How can I extract theOutput from page.evaluate?
Since this is a blocking AJAX request, you can create a temporary variable:
var theOutput = page.evaluate(function () {
var result;
$.ajax({
async: false,
...
success: function (output) {
parsed_output = $.parseHTML(output);
result = parsed_output[4].data.trim();
},
});
return result;
});
console.log(theOutput);
You can also directly access the responseText from the jqXHR object:
var theOutput = page.evaluate(function () {
var jqXHR = $.ajax({
async: false,
url: 'http://localhost:8080/captcha.php',
data: { filename: 'C:\\wamp\\www\\images\\0.png' },
type: 'post'
});
parsed_output = $.parseHTML(jqXHR.responseText);
return parsed_output[4].data.trim();
});
console.log(theOutput);
If you fear that async: false is deprecated, you can simply use the underlying XMLHttpRequest to use blocking execution:
var theOutput = page.evaluate(function () {
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:8080/captcha.php', false);
request.send($.param({ filename: 'C:\\wamp\\www\\images\\0.png' }));
var parsed_output = $.parseHTML(request.responseText);
return parsed_output[4].data.trim();
});
console.log(theOutput);
ajax.postJson(
"/foo/GetFoo",
{ fooName: fooName },
function (data) {
},
function (error) { });
};
My Rest api call is GetAsync()
It throws ajax is undefined : JavaScript runtime error: Unable to get property 'exceptionStart' of undefined or null reference. The custom code to make ajax call is below. The api call Getfoo is GetAsync method using attribute HttpGet. Can someone point me to the cause of this failure
var ajax = {
defaultAjaxTimeout: 600000,
exceptionStart: '<!--',
exceptionEnd: '-->',
postJson: function (url, data, success, error) {
$.ajax(
{
type: "POST",
dateType: "json",
url: url,
data: data,
timeout: ajax.defaultAjaxTimeout,
success: function (result) {
if (success) success(result);
},
error: function (jqXhr, textStatus, errorThrown) {
if (error && jqXhr) {
var responseText = jqXhr.responseText;
var index = responseText.indexOf(ajax.exceptionStart);
if (index > 0) {
var exception = responseText.substr(index + ajax.exceptionStart.length + 1);
index = exception.lastIndexOf(ajax.exceptionEnd);
if (index > 0) {
exception = exception.substr(0, index);
}
error(exception);
} else {
error(errorThrown);
}
}
}
});
},
}
The issue you're having here is that you're attempting to access the variable ajax from a closure before it's created:
var myVariable = {
myProperty: "Hello",
myFunction: function () {
//... access myVariable.myProperty -> error
}
};
There are two options here. The cleaner one, and the one I'd use is this:
var ajaxOptions = {
defaultAjaxTimeout: 600000,
exceptionStart: '<!--',
exceptionEnd: '-->'
};
var ajax = {
postJson: function (url, data, success, error) {
... ajaxOptions.exceptionStart.length
}
};
The reason this works is because ajaxOptions exists already in the scope where you declare the function ajax.postJson so it's able to reference it correctly from its closure.
The variation on this option is this:
var ajax = {
defaultAjaxTimeout: 600000,
exceptionStart: '<!--',
exceptionEnd: '-->'
};
ajax.postJson = function (url, data, success, error) {
... ajax.exceptionStart.length
};
The reason this works is because ajax is already declared, and is just attached to the closure of the function.
A second, less-clean option is to put the ajax variable as a child of the window object:
window.ajax = {
defaultAjaxTimeout: 600000,
exceptionStart: '<!--',
exceptionEnd: '-->',
postJson: function (url, data, success, error) {
... window.ajax.exceptionStart.length
}
};
The reason this works is because window always exists in all lexical scopes, so it'll have no problem referencing it. The reason it's less clean is because it pollutes the window object and any JavaScript anywhere on your page can access and change it, potentially causing unknown behavior. I'm not recommending it, I'm just providing it as an example.
The following steps helped me resolve similar problem, I used IE11
the solution to it in IE 11 can be:
under internet settings select 'Compatibility View settings',
in 'Add this website' enter server name for your website (for example: localhost ), click 'Add' btn.
Tick 'Display intranet steps in Compatibility View' box.
Below you will see some code to set the currently logged in user for an extjs 4 application. If I have the alert uncommented, the code seems to wait until the alert is accepted before the code continues (it seems). That allows enough time for the asynchronous call to complete with a success. If I comment out the alert, the variable "employeeFilter" never gets set because the AJAX call didn't come back in time. In which case, it sets the "employeeFilter" to null instead. How can I fix this so it waits until the AJAX response comes back in success?
var loggedInUserId = null;
Ext.Ajax.request({
url: '/Controls/UserList/UserService.asmx/GetLoggedInUserId',
method: 'POST',
jsonData: { 'x': 'x' },
success: function (response, opt) {
loggedInUserId = Ext.decode(response.responseText).d;
},
failure: function (response) {
}
});
//alert(loggedInUserId);
var employeeFilter = loggedInUserId;
var projectFilter = '-1';
I would have done this.
var employeeFilter;
Ext.Ajax.request({
url: '/Controls/UserList/UserService.asmx/GetLoggedInUserId',
method: 'POST',
jsonData: { 'x': 'x' },
success: function (response, opt) {
employeeFilter = Ext.decode(response.responseText).d;
//Do here whatever you need to do once the employeeFilter is set. probably call a function and pass the employee filter as parameter.
},
failure: function (response) {
}
});
var projectFilter = '-1';
I'm trying to create a global handler that gets called before the ajax success callback. I do a lot of ajax calls with my app, and if it is an error I return a specific structure, so I need to something to run before success runs to check the response data to see if it contains an error code bit like 1/0
Sample response
{"code": "0", "message": "your code is broken"}
or
{"code": "1", "data": "return some data"}
I can't find a way to do this in jQuery out of the box, looked at prefilters, ajaxSetup and other available methods, but they don't quite pull it off, the bets I could come up with is hacking the ajax method itself a little bit:
var oFn = $.ajax;
$.ajax = function(options, a, b, c)
{
if(options.success)
{
var oFn2 = options.success;
options.success = function(response)
{
//check the response code and do some processing
ajaxPostProcess(response);
//if no error run the success function otherwise don't bother
if(response.code > 0) oFn2(response);
}
}
oFn(options, a, b, c);
};
I've been using this for a while and it works fine, but was wondering if there is a better way to do it, or something I missed in the jQuery docs.
You can build your own AJAX handler instead of using the default ajax:
var ns = {};
ns.ajax = function(options,callback){
var defaults = { //set the defaults
success: function(data){ //hijack the success handler
if(check(data)){ //checks
callback(data); //if pass, call the callback
}
}
};
$.extend(options,defaults); //merge passed options to defaults
return $.ajax(options); //send request
}
so your call, instead of $.ajax, you now use;
ns.ajax({options},function(data){
//do whatever you want with the success data
});
This solution transparently adds a custom success handler to every $.ajax() call using the duck punching technique
(function() {
var _oldAjax = $.ajax;
$.ajax = function(options) {
$.extend(options, {
success: function() {
// do your stuff
}
});
return _oldAjax(options);
};
})();
Here's a couple suggestions:
var MADE_UP_JSON_RESPONSE = {
code: 1,
message: 'my company still uses IE6'
};
function ajaxHandler(resp) {
if (resp.code == 0) ajaxSuccess(resp);
if (resp.code == 1) ajaxFail(resp);
}
function ajaxSuccess(data) {
console.log(data);
}
function ajaxFail(data) {
alert('fml...' + data.message);
}
$(function() {
//
// setup with ajaxSuccess() and call ajax as usual
//
$(document).ajaxSuccess(function() {
ajaxHandler(MADE_UP_JSON_RESPONSE);
});
$.post('/echo/json/');
// ----------------------------------------------------
// or
// ----------------------------------------------------
//
// declare the handler right in your ajax call
//
$.post('/echo/json/', function() {
ajaxHandler(MADE_UP_JSON_RESPONSE);
});
});
Working: http://jsfiddle.net/pF5cb/3/
Here is the most basic example:
$.ajaxSetup({
success: function(data){
//default code here
}
});
Feel free to look up the documentation on $.ajaxSetup()
this is your call to ajax method
function getData(newUrl, newData, callBack) {
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: newUrl,
data: newData,
dataType: "json",
ajaxSuccess: function () { alert('ajaxSuccess'); },
success: function (response) {
callBack(true, response);
if (callBack == null || callBack == undefined) {
callBack(false, null);
}
},
error: function () {
callBack(false, null);
}
});
}
and after that callback success or method success
$(document).ajaxStart(function () {
alert('ajax ajaxStart called');
});
$(document).ajaxSuccess(function () {
alert('ajax gvPerson ajaxSuccess called');
});