Jquery Ajax, not working in Internet explorer - asp.net

I'm trying to do some jQuery ajax and it works in Firfox and Chrome, but not in internet explorer 9.
The final code will have to go across sub-domains, and this doesn't work in ie with the default transport.
So I'm trying to create a custom transport to use in internet explorer
Method 1
$.ajaxTransport("+*", function (options, originalOptions, jqXHR) {
if (jQuery.browser.msie && window.XDomainRequest) {
var xdr;
return {
send: function (headers, completeCallback) {
// Use Microsoft XDR
xdr = new XDomainRequest();
xdr.open("get", options.url);
xdr.onload = function () {
if (this.contentType.match(/\/xml/)) {
var dom = new ActiveXObject("Microsoft.XMLDOM");
dom.async = false;
dom.loadXML(this.responseText);
completeCallback(200, "success", [dom]);
} else {
completeCallback(200, "success", [this.responseText]);
}
};
xdr.ontimeout = function () {
completeCallback(408, "error", ["The request timed out."]);
};
xdr.onerror = function () {
completeCallback(404, "error", ["The requested resource could not be found."]);
};
xdr.send();
},
abort: function () {
if (xdr) xdr.abort();
}
};
}
});
I've created a simple sample page to demonstrate the first technique here:
http://services.whygo.net/sendAjax.htm
Please note if you use the custom transport the normal transport will then fail unless you refresh
The idea comes from here:
http://forum.jquery.com/topic/cross-domain-ajax-and-ie#14737000002203097
This give no error message other than 'error' inside the 'error' method called on $ajax, when it fails. I do get a 405 Method not allowed on the 'Network' tab of if dev tools, but the server side stuff does execute.
Method 2
I have also tried another method as described here:
Cross-subdomain AJAX works in Chrome, not IE
if ('XDomainRequest' in window && window.XDomainRequest !== null) {
// override default jQuery transport
jQuery.ajaxSettings.xhr = function() {
try { return new XDomainRequest(); }
catch(e) { }
};
}
This can be found here:
http://www.whygo.net/sendAjax2.html
On this one I actually get 200 codes on the 'network' tab of ie dev tools, but doesn't call the 'error' or the 'success' pararm of $ajax.
If I put a timeout on this second one, then it returns to the 'error' function with a message of 'timeout'.

Here's the solution I went with after about a day of struggling with this inconsistency...
// new method as to not overwrite jQuery's defaults
var cors = (window.XDomainRequest) ? function(url, callback) {
var xdr = new XDomainRequest();
xdr.open('get', url);
xdr.onload = function() { callback(xdr.responseText); }
xdr.send();
} : $.get; // else, use jQuery's method
Use...
cors(url, function(msg) { alert(msg); }); // pretty well same as $.get
Copy and paste, this of course doesn't serve all purposes, but it's a start and it works.

On the http://services.whygo.net/sendAjax2.html page, I see that you've got the expected dataType of the AJAX response coming back from the server as JSON, but the response actually comes back as a plain text string ("Email successfully sent.").
Perhaps you could try commenting out dataType and let jQuery figure out what type of response comes back.

Related

How to reset X-editable fields after save event

This is a follow-up question to this answer in https://stackoverflow.com/a/15121394/2247553 on which I cannot comment yet due to the reward system at StackOverflow.
My question is, after the collection update has been requested with Meteor, how do I reset the editable back to its original state in case the server rejects the update?
Template.editableTable.rendered = function() {
$('#myParentTable').editable({
selector: '.editable-click'
});
$('a.editable-click').unbind('save').on('save', function(e, params) {
MyCollection.update({_id: 'myid'}, {$set: {key: 'val'}}, function(error, docs) {
if (error) {
// how do I reset X-editable here?
}
});
});
};
According to the FAQ, if the server side validation fails, you should return a non 200 status.
I know this doesn't exactly answer your question. I'm trying to do the same thing, return a success:false status. It does act like an API in a way, so sending back a 200 suggests that everything worked ok, so it updates the value. The request is to update the value, 200 status is for success.
Hope that makes sense. Please comment if you would like clarification.
My code for the error param of the editable function is below...
error: function(response, newValue) {
var json = false;
try {
json = JSON.parse(response.responseText);
} catch (e) {
json = false;
}
//Bootstrap message is my own thing.
bootstrapMessage.init('#search_results');
if(response.status === 500) {
bootstrapMessage.show_message('There is a server error. Please contact our supoprt team.', 'danger');
} else {
if(json){
bootstrapMessage.show_message(json.message, 'danger');
}else{
bootstrapMessage.show_message('Problem saving your change. Please refresh the page and try again or contact our support team', 'danger');
}
}
}

AngularJS - refresh view after http request, $rootScope.apply returns $digest already in progress

I am simply trying to load data when my app starts. However, the view loads faster than the http request(of course). I want to refresh my view once my data has been properly loaded because that data defines my view.
I've tried $rootScope.apply from inside the factory where I do my http request, and I also tried directly doing the http request in my controller again with $scope.apply, and neither one worked as they both gave me "$digest already in progress"
Any idea how can I set up my code to make my views refresh on data load? I will be having several different http requests and I would like to know how to set them up properly! I would really appreciate any input!
Here is some of the code I am working with.
app.factory('HttpRequestFactory', function($http, $q) {
var HttpRequestFactory = {
async: function(url, params) {
var deferred = $q.defer();
$http({
url: url,
method: post,
params: params
})
.success(function(data, status, headers, config) {
deferred.resolve(data);
})
.error(function(data, status, headers, config) {
deferred.reject("An error occurred");
});
return deferred.promise;
}
};
return HttpRequestFactory;
});
Factory
function initializeAll(){
HttpRequestFactory.async('../api', {action: 'getall'}).then(function(data) {
//$rootScope.$apply(function () {
allData = data;
//});
angular.forEach(allData, function(value, index){
console.log('Voala!');
});
});
}
Controller calling the factory's function initializeAll()
app.controller("MainController", ["$scope", "$rootScope","MyFactory",
function($scope, $rootScope, MyFactory){
MyFactory.initializeAll();
}
]);
Oh my !
You got the f** matter with AngularJS !
In fact you have to do a "safeApply" like that for example :
$rootScope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
In AngularJS you can only have one $apply or $digest loop at the same time.
For details on these loops look at the docs :
http://docs.angularjs.org/guide/concepts
It will explain what is the $apply loop and you'll understand a lot of things about the two-way-data-binding in AngularJS
Hope it helps.
Don't use $apply: use $watch.
Calling $apply is (almost) always the wrong thing to do. The only time you should ever be calling it is if you've triggered a change outside of an 'angular' method; here, since the trigger occurs in an angular $http request, you can't call $apply because it's already being done at that moment by the $http block. Instead, what you want to do is $watch.
Official Doc for $scope.$watch() here
This will let you watch an object and update whenever it changes. I assume that your view is based on allData and you want it to update immediately; if you're using an ng method, then the watch is automatically setup for you and no more work should be needed. If you're using allData yourself inside a controller, you can write the watch in that controller like this:
$scope.$watch(function thingYouWantToWatch(){
return <accessor call to allData here>;
},
function whatToDoOnChange(newValue, oldValue){
$scope.myCoolThing = newValue; //this is the newValue of allData, or whatever you're watching.
}
);

Issue binding JSONP data with Knockout.js

I am working on a web project that involves a cross-domain call, and I decided to use Knockout.js and ASP.NET Web Api. I used the Single Page Application template in VS 2012, and implemented the Knockout class as it is. The page works great when I make JSON call from the same domain, but when I try using JSONP from the remote server the knockout does not seem to bind the data. I can see the JSON data received from the remote while making JSONP call, but knockout cannot bind the data.
Here is my JavaScript ViewModel classes:
window.storyApp.storyListViewModel = (function (ko, datacontext) {
//Data
var self = this;
self.storyLists = ko.observableArray();
self.selectedStory = ko.observable();
self.error = ko.observable();
//Operations
//Load initial state from the server, convert it to Story instances, then populate self
datacontext.getStoryLists(storyLists, error); // load update stories
self.selectStory = function (s) {
selectedStory(s); $("#showStoryItem").click(); window.scrollTo(0, 0);
storyItem = s;
}
//append id to the hash for navigating to anchor tag
self.backToStory = function () {
window.location.hash = storyItem.id;
}
self.loadStories = function () {
datacontext.getStoryLists(storyLists, error); // load update stories
}
return {
storyLists: self.storyLists,
error: self.error,
selectStory: self.selectStory
};
})(ko, storyApp.datacontext);
// Initiate the Knockout bindings
ko.applyBindings(window.storyApp.storyListViewModel);
And my DataContext class as below:
window.storyApp = window.storyApp || {};
window.storyApp.datacontext = (function (ko) {
var datacontext = {
getStoryLists: getStoryLists
};
return datacontext;
function getStoryLists(storyListsObservable, errorObservable) {
return ajaxRequest("get", storyListUrl())
.done(getSucceeded)
.fail(getFailed);
function getSucceeded(data) {
var mappedStoryLists = $.map(data, function (list) { return new createStoryList(list); });
storyListsObservable(mappedStoryLists);
}
function getFailed() {
errorObservable("Error retrieving stories lists.");
}
function createStoryList(data) {
return new datacontext.StoryList(data); // TodoList is injected by model.js
}
}
// Private
function clearErrorMessage(entity) {
entity.ErrorMessage(null);
}
function ajaxRequest(type, url, data) { // Ajax helper
var options = {
dataType: "JSONP",
contentType: "application/json",
cache: false,
type: type,
data: ko.toJSON(data)
};
return $.ajax(url, options);
}
// routes
function storyListUrl(id) {
return "http://secure.regis.edu/insite_webapi/api/story/" + (id || "");
}
})(ko);
This page: http://insite.regis.edu/insite/index.html makes the cross-domain call to secure.regis.edu, and it is not working. However the same page on secure.regis.eduinsite/index.html making JSON call works just fine.
What am I doing wrong? Any help will be greatly appreciated.
Thanks for those provided help.
I manage to solve the issue by adding WebApiContrib.Formatting.Jsonp class to my WebApi project as explained in https://github.com/WebApiContrib/WebApiContrib.Formatting.Jsonp, and making a slight modification to my jQuery Ajax helper class as below:
function ajaxRequest(type, url, data, callbackWrapper) { // Ajax helper
var options = {
dataType: "jsonp",
crossDomain : true,
type: type,
jsonp: "callback",
jsonpCallback: callbackWrapper,
data: ko.toJSON(data)
};
return $.ajax(url, options);
}
Everything worked as a charm.
I suggest the following:
Create a simplified example (without Knockout) that just makes the AJAX call with simple, alert-style success and error callbacks. Affirm that it is throwing an error in the cross-domain case.
Check the following link: parsererror after jQuery.ajax request with jsonp content type. If that doesn't tell you enough, search the Web (and StackOverflow) for information on jQuery JSONP parserrors and callbacks.
If you're still stuck, and you've done #1 and seen what I expect you will see, re-write this post with your simplified example, and remove any references to Knockout (in title, tags). I know Knockout, but I don't know JSONP, and the folks who know JSONP don't seem to be touching this, so I think this question is reaching the wrong audience. Changing the title and tags to emphasize the JSONP/cross-domain aspect may get you the help you need.

XDomainRequest in IE is giving Access is Denied error

This is the code I am using is as follows down below:
I am using IE9 and am unable to see the request being sent in the Network tab. I do have Access-Control headers set in the JSP as:
<% response.setHeader("Access-Control-Allow-Origin", "*");%>
Code to get the AJAX HTML Content from the JSP:
if ($.browser.msie && window.XDomainRequest) {
var xdr = new window.XDomainRequest();
xdr.open("GET", "http://dev01.org:11110/crs/qw/qw.jsp?&_=" + Math.random());
xdr.contentType = "text/plain";
xdr.timeout = 5000;
xdr.onerror = function () {
console.log('we have an error!');
}
xdr.onprogress = function () {
console.log('this sucks!');
};
xdr.ontimeout = function () {
console.log('it timed out!');
};
xdr.onopen = function () {
console.log('we open the xdomainrequest');
};
xdr.onload = function() {
alert(xdr.responseText);
};
xdr.send(null);
} else { ...... }
I am getting a Access is Denied Error. Any help would be much appreciated!
Requests must be targeted to the same scheme as the hosting page
In your example you are doing request to:
http://dev01 ...
And you should do this from HTTP protocol.
For example:
If your site, where js script is located: http://dev.org
You can do this:
xhr = new XDomainRequest();
xhr.open("GET", "http://dev01.org?p=1");
but this throws "Access denied":
xhr = new XDomainRequest();
xhr.open("GET", "https://dev01.org?p=1");
My experience with XDomainRequest is that it doesn't respect Access-Control-Allow-Origin: *. Instead, you must specify the domain. This can be obtained from the HTTP_REFERER header if you need to dynamically generate it, or if you are only expecting requests from one domain you can set it manually. This article might help.
<% response.setHeader("Access-Control-Allow-Origin", "http://dev01.org");%>

Dealing with context of server responses in realtime web applications

Finding it hard to describe this issue - so please edit if you know more relevant terms.
I'm building a web application which essentially uses Redis (PubSub) + Node.js + Socket.IO as a distribution server.
I have two-way communication working with no issues - but I need to be able to make a request to the server from the client (asynchronously) and deal with the response while still processing other irrelevant responses that might come in before it.
This is what I have so far, but I'm not particularly happy with this approach:
Server
// Lots of other code
redis.psubscribe('*');
redis.on("pmessage", function(pattern, channel, message) {
// broadcast
});
io.on('connection', function(client) {
client.on('message', function(message) {
switch(message.method) {
// call relevant function
}
});
});
function object_exists(object_id) {
// do stuff to check object exists
client.send({method: 'object_exists', value: object_exists});
}
Client
var call = Array();
$(document).ready(function() {
socket.connect();
socket.on("message", function(obj){
console.log(obj);
call[obj.method](obj.value);
});
});
function object_exists(object_id) {
socket.send({method: 'object_exists', value: object_id});
// Set a function to be called when the next server message with the 'object_exists' method is received.
call['object_exists'] = function(value) {
if(value) {
// object does exist
}
}
}
tl;dr: I need to 'ask' the server something and then deal with the response using Socket.IO.
You don't specifically say why you are unhappy with your approach, but it looks to me like you are almost there. I am not really sure what you are trying to do with the call array, so I just took it out for clarity.
Basically, you just need to set up a switch statement to act as a message router on each side of the socket connection and fire off the appropriate methods based in incoming messages. Send enough state with the message itself so you can handle the work without any additional context. In your reworked code, I send the object_id to the server and back again to the client.
///SERVER
// Lots of other code
redis.psubscribe('*');
redis.on("pmessage", function(pattern, channel, message) {
// broadcast
});
io.on('connection', function(client) {
client.on('message', function(message) {
switch(message.method) {
case 'object_exists':
object_exists(message.objectId);
break;
}
});
});
//Takes an id an returns true if the object exists
function object_exists(object_id) {
// do stuff to check object exists
client.send({method: 'object_exists', objectId: object_id, value: object_exists});
}
///CLIENT
$(document).ready(function() {
//setup the message event handler for any messages coming back from the server
//This won't fire right away
socket.on("message", function(message){
switch(message.method) {
case 'object_exists':
object_exists(message.objectId, message.value);
break;
}
});
//When we connect, send the server the message asking if object_exists
socket.on("connect", function() {
socket.send({method: 'object_exists', objectId: object_id});
});
//Initiate the connection
socket.connect();
});
//Get's called with with objectId and a true if it exists, false if it does not
function object_exists(objectId, value) {
if(value) {
// object does exist, do something with objectId
}
else {
// object does not exist
}
}
If you want to see a bunch more code in the same stack doing work similar to what you are trying to accomplish, check out my nodechat.js project.

Resources