Strange Ajax behavior in JQuery in Opera and Chrome - javascript

I have this functions
//send JSON-RPC request
var json_rpc = (function() {
var id = 1;
return function(url, method, params, success) {
if (typeOf(params) != 'array') {
params = [params];
}
var request = JSON.stringify({
'jsonrpc': '2.0',
'method': method,
'params': params,
'id': id++});
return $.ajax({
url: url,
data: request,
success: success,
error: function (XMLHttpRequest, textStatus, errorThrown) {
error_msg('XHR error ' + XMLHttpRequest.status + ' ' +
XMLHttpRequest.responseText);
},
beforeSend: function(xhr) {
console.log('before send');
console.log(dir(xhr));
xhr.onreadystatechange = function(){
console.log('state');
};
},
contentType: 'application/json',
dataType: 'json',
type:"POST"});
}
})();
var rpc = function(method, success_callback) {
//I use functional javascript library
var fun = json_rpc.partial('rpc.php', method, _, function(data) {
if (data['error']) {
var e = 'Json-RPC (' + method + ') ' + data['error']['code'] + ": " +
data['error']['message'];
error_msg(e);
} else {
info_msg("rpc sucess for method '" + method + "'");
success_callback(data['result']);
}
});
return function() {
fun(Array.slice(arguments));
};
};
and when I create function with rpc
var update_news = rpc('get_news', function(data) {
if (data) {
//update news
}
});
and call it
$(document).ready(function() {
...
update_news();
...
});
In Firefox everythig is fine, but in Opera and Chrome the function update_news is not executing, beforeSend is fired but onreadystatechange is not, but when I add
setTimeout(update_news, 0);
Then It's call normaly, also when I create synchronous call by putting async: false in $.ajax call or when I put timeout, timeout: 1. In click handlers it also run as expected.
$('#some_id').click(function() {
update_news();
});
Anybody know why this is happening.

Related

Returning the correct promise in angular

I'm having trouble returning the correct promise for a service in angular.
this is my function:
postToSP.post($scope.sharePointURL, data).then(function() {
$scope.gettingData = false;
$scope.yammerListName = "Successfully posted to SP";
}).catch(function(e){
//console.log("Error: ", e);
$scope.yammerListName = "Sorry we couldn't post to that page, please make sure your column names are EXACTLY the same!"
$scope.gettingData = false;
throw e;
});
And this is my service, i get the error: "Unable to get property 'then' of undefined or null reference". I know it's because i'm not returning the promise properly but I can't figure out how to do it correctly. Please help, thanks in advance.
app.service("postToSP", function($http) {
//Submit to SP function
this.post = function(originalurl,data){
console.log(data);
var url = originalurl.split("Lists/")[0];
var listname = originalurl.split("Lists/")[1].split("/")[0];
//if the row is checked send it, if not jump to the next row
//run the function, continue until the end and break
var i = 0;
return letsPost(i);
function letsPost (i) { //i<data.length; i++
if (data[i].checked == false) {
i++;
return letsPost(i);
} else {
var formattedText = document.getElementById("text"+i).innerHTML.toString() ;
var formattedCreated = document.getElementById("created"+i).innerHTML.toString();
var formattedLikes = document.getElementById("likes"+i).innerHTML.toString();
var formattedLinks = document.getElementById("links"+i).innerHTML.toString();
var uploadData = { //change this for input data
'__metadata': { 'type': 'SP.Data.' + listname + 'ListItem' },
'Title': i + "",
'Likes': formattedLikes,
'Post_x0020_Date': formattedCreated,
'Post_x0020_Links' : formattedLinks,
'Post_x0020_Text': formattedText
};
console.log(uploadData);
createListItem(url, listname, uploadData)
.done(function (columnData) {
console.log('Added row' + i);
// if there is more data
if (i < data.length) {
i++;
return letsPost(i);
//add new data and continue the function
} else {
return;
}
})
.fail(function (error) {
console.log(JSON.stringify(error));
alert("Error:" + JSON.stringify(error));
throw error;
});
//Function to get form digest token
function getFormDigest(webUrl) {
return $.ajax({
url: webUrl + "/_api/contextinfo",
method: "POST",
headers: { "Accept": "application/json; odata=verbose" }
});
};
//Function to create the list item
function createListItem(webUrl, listName, itemProperties) {
$.ajax({
url: url + "/_api/web/lists/getbytitle('" + listName + "')/items",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
console.log(data.d.results);
},
error: function (data) {
console.log(data);
}
});
return getFormDigest(webUrl).then(function (data) {
return $.ajax({
url: webUrl + "/_api/web/lists/getbytitle('" + listName + "')/items",
type: "POST",
processData: false,
contentType: "application/json;odata=verbose",
data: JSON.stringify(itemProperties),
headers: {
"Accept": "application/json;odata=verbose",
"X-RequestDigest": data.d.GetContextWebInformation.FormDigestValue
}
});
});
};
};
};
};
});
in your function declare the promise first
this.post = function(originalurl,data){
var deferred = $q.defer();
the data that you want to return use
deferred.resolve(dataToReturn)
and at the end of your function add
return deferred.promise;
From what I understand your code, mistake you are doing is you are returning the promise returned from getFormDigest but also applying then function on it and returning another promise. If you dont return getFormDigest nothing will be returned since its async.
To solve it you can use angular $q library and return and independent promise. Resolve that promise in your then function where you are returning a promise and no need to return getFormDigest so only one promise will be returned and hopefully your problem will be resolved.
In simple way you can achieve it..i hope it make sense
//in your controller
yourService.addData(yourPayload);
.then(function (cou) {
$scope.data = cou.data;
});
//in your service
this.addData = function (data) {
var response = $http({
method: "POST",
url: 'your url',
data: data,
dataType: "json"
});
return response;
}

Unable to get access and refresh token after authenticating with Google API

I followed this awesome tutorial to get the access and refresh tokens once the user logged in with their google account, but I always this response when I call GetAccessCode():
{
"error": "invalid_request"
}
Here's my code:
var url = window.location.href;
if (url.indexOf("code=") > 0) { //Once the user signed in with Google
var code_starts = url.indexOf("code=");
var code = url.substring((code_starts + 5), url.length);
alert("Code= " + code);
GetAccessTokens(code);
} else if (url.indexOf("access_token=") > 0) { //Get the tokens, but I never get this far
var at_starts = url.indexOf("access_token=");
var exp_starts = url.indexOf("expires_in=");
var access_token = url.substring((at_starts + 13), exp_starts);
alert("AT= " + access_token);
var rt_starts = url.indexOf("refresh_token=");
var id_starts = url.indexOf("id_token=");
var refresh_token = url.substring((rt_starts + 14), id_starts);
alert("RT= " + refresh_token);
} else {
GetAccessCode(); //If user opens the page, show him the consent screen
}
function GetAccessCode() {
window.location = 'https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=https://mywebsite.com/quickstart.html' + '&response_type=code' + '&client_id=' + clientId + '&scope=' + scopes + '&approval_prompt=force' + '&access_type=offline';
}
function GetAccessTokens(code) {
window.location = 'https://accounts.google.com/o/oauth2/token?code=' + code + '&client_id=' + clientId + '&client_secret=' + clientSecret + '&redirect_uri=https://mywebsite.com/quickstart.html' + '&grant_type=authorization_code';
}
Here I receive the invalid_request error.
I tried to get the tokens via an ajax request to not have to redirect the page again (bad UX):
var red = 'https://mywebsite.com/quickstart.html';
var options = {
url: 'https://accounts.google.com/o/oauth2/token',
type: "POST",
dataType: "json",
data: "code=code&client_id=clientId&client_secret=clientSecret&redirect_uri=red&grant_type=authorization_code",
complete: function (e) {
alert(e);
alert(e.status);
},
};
$.ajax(options);
}
I tried it with headers, too:
headers: { "Content-type": "application/x-www-form-urlencoded"},
And I tried it this way, too:
$.ajax({
url: "https://accounts.google.com/o/oauth2/token",
type: "post",
datatype:"json",
contentType: "application/x-www-form-urlencoded; charset=utf-8",
async : true,
data: {code:code, client_id:clientId, client_secret:clientSecret, redirect_uri:'https://mywebsite.com/quickstart.html', grant_type:'authorization_code'},
success: function(response){
alert(response); //I never get this
var json = $.parseJSON(response);
}
})
.fail(function(err) {
alert("error" + err); //I get [Object object]
});
And a few other stuff, too.
Oh, and all the parameters have the correct value.
Any ideas?
Ps: The oauth playground shows that the corrent token url is https://www.googleapis.com/oauth2/v4/token but when I use it I get Not found in the browser.
After 3 days I did it. Thanks for the console.log tip, #Brunt!
$.ajax({
url: 'https://www.googleapis.com/oauth2/v4/token',
type: "post",
datatype:"json",
contentType: "application/x-www-form-urlencoded; charset=utf-8",
async : true,
data: {code:code, client_id:clientId, client_secret:clientSecret, redirect_uri:'https://mywebsite.com/quickstart.html', grant_type:'authorization_code'},
success: function(response){
console.log("Response: " + response);
console.log("AT: " + response['access_token']);
console.log("RT: " + response['refresh_token']);
access_token = response['access_token'];
refresh_token = response['refresh_token'];
}
})
.fail(function(err) {
alert("error" + err); //[Object object]
console.log("error" + err);
});

Select2: Uncaught TypeError: options.results is not a function

I am attempting to do an AJAX call with the Select2 jquery plugin. The query seems to be working, but the issue occurs when .results() is called on the options object:
Uncaught TypeError: options.results is not a function
Here is my HTML:
<input class="form-control" type="number" value="2125" name="topic_relation[source_topic_id]" id="topic_relation_source_topic_id" />
Here is my JS:
$(document).ready(function() {
$('#topic_relation_source_topic_id').select2({
minimumInputLength: 3,
ajax: {
url: "<%= grab_topics_path %>",
dataType: 'json',
delay: 250,
data: function (term, page) {
return {
q: term, //search term
page_limit: 30, // page size
page: page, // page number
};
},
processResults: function (data, page) {
var more = (page * 30) < data.total;
return {results: data.topics, more: more};
}
},
formatResult: topicFormatResult,
formatSelection: formatRepoSelection,
escapeMarkup: function (m) { return m; }
});
function topicFormatResult(topic) {
return topic.name
}
function formatRepoSelection(topic) {
return '<option value="'+ topic.id +'">' + topic.name + '</option>'
}
});
Here is the returned JSON:
{"total":2, "topics":[{"id":305,"name":"Educational Assessment, Testing, And Measurement"},{"id":3080,"name":"Inspectors, Testers, Sorters, Samplers, And Weighers"}]}
Here is the code which is failing:
function ajax(options) {
var timeout, // current scheduled but not yet executed request
handler = null,
quietMillis = options.quietMillis || 100,
ajaxUrl = options.url,
self = this;
return function (query) {
window.clearTimeout(timeout);
timeout = window.setTimeout(function () {
var data = options.data, // ajax data function
url = ajaxUrl, // ajax url string or function
transport = options.transport || $.fn.select2.ajaxDefaults.transport,
// deprecated - to be removed in 4.0 - use params instead
deprecated = {
type: options.type || 'GET', // set type of request (GET or POST)
cache: options.cache || false,
jsonpCallback: options.jsonpCallback||undefined,
dataType: options.dataType||"json"
},
params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated);
data = data ? data.call(self, query.term, query.page, query.context) : null;
url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url;
if (handler && typeof handler.abort === "function") { handler.abort(); }
if (options.params) {
if ($.isFunction(options.params)) {
$.extend(params, options.params.call(self));
} else {
$.extend(params, options.params);
}
}
$.extend(params, {
url: url,
dataType: options.dataType,
data: data,
success: function (data) {
========> var results = options.results(data, query.page, query); <==========
query.callback(results);
},
error: function(jqXHR, textStatus, errorThrown){
var results = {
hasError: true,
jqXHR: jqXHR,
textStatus: textStatus,
errorThrown: errorThrown
};
query.callback(results);
}
});
handler = transport.call(self, params);
}, quietMillis);
};
}
Since the plugin calls results(), you should also declare results: function (data, page) instead of processResults: function (data, page).

Unable to cache ajax data on document.ready()

I am using following code to fetch and cache data from a ASP.NET handler. The problem is that whenever I cache data using a button click its working fine, but I want this to happen at document.ready() event. When I executed this code on document.ready() event, its fetching data perfectly, but its not getting data from the cache when I reload the page.
var localCache = {
data: {},
remove: function (url) {
delete localCache.data[url];
},
exist: function (url) {
return localCache.data.hasOwnProperty(url) && localCache.data[url] !== null;
},
get: function (url) {
console.log('Getting in cache for url' + url);
return localCache.data[url];
},
set: function (url, cachedData, callback) {
cacheTime = (new Date()).getTime();
localCache.remove(url);
localCache.data[url] = cachedData;
if ($.isFunction(callback)) callback(cachedData);
}
};
var now;
var cacheTime;
var tDiff;
function getValueAtIndex(index) {
var str = window.location.href;
return str.split("/")[index];
}
//$(document).ready(function () {
$('#Button1').click(function (e) {
var url = '/Handlers/ResponseFetcher.ashx';
var topicid = "<%=desid %>";
$.ajax({
url: url,
type: "POST",
data:
JSON.stringify({ tid: topicid })
,
dataType: "json",
cache: true,
beforeSend: function () {
now = (new Date()).getTime();
if (localCache.exist(url)) {
tDiff = now - cacheTime;
if (tDiff < 20000) {
loadData(localCache.get(url));
return false;
}
}
return true;
},
complete: function (jqXHR, textStatus) {
localCache.set(url, jqXHR, loadData);
}
});
});
function loadData(data) {
console.log("now: " + now + ", cacheTime: " + cacheTime + ", tDiff:" + (cacheTime - now));
$('#responseloader').hide();
var resdata = JSON.parse(data.responseText);
$(resdata).each(function (i) {
$('#responsecontainer').append("<div>" + this.Title + "</div>");
});
}
Here tDiff will be undefined on first run. Is this the problem? or caching doesn't work if the page is reloaded? Please help!

handle jquery ajax error

in my MVC layout page I have the following:
$("body").ajaxError(
function (e, request) {
if (request.status == 403 || request.status == 500) {
window.location = '#Url.Action("LogOn", "Account", new {area = "", msg = "forbidden", returnUrl = HttpContext.Current.Request.RawUrl})' + window.location.hash;
return;
}
window.location = '#Url.Action("Index", "Error")';
}
);
on another page I'm performing an ajax call like so:
...
$.when(refreshActionLinks(row, machineId, packageId)).done(function(a1) {
row.find("span").text(opStatus).removeClass("pending");
progressbar.progressbar("destroy");
$(row).flash(bg[1], 1000);
});
...
javascript function:
function refreshActionLinks($row, machineId, packageId) {
try {
var json = JSON.stringify({ packageId: packageId, machineId: machineId, tabType: $("#TabType").val() });
console.log("refreshActionLinks => " + json);
$row.find("td.options div.actionLinks").html("<img src='#Url.Content("~/Content/images/ajax-load2.gif")' />"); // pending
return $.ajax({
url: "#Url.Action("GetActionLinks", "Packages")",
data: json,
timeout: 50000,
contentType: 'application/json',
type: 'POST',
success: function (data) {
if ($row.length) {
$row.find("td.options div.actionLinks").html(data);
}
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
}
});
} catch(e) {
// hide icons
$row.find("a.action").remove();
}
}
The issue is that while refreshAction function is executing, clicking a menu link causes the ajax call to error out - which in this case is correct. BUT it does take me to /Index/Error page which is NOT correct. I would like "$("body").ajaxError" to handle all ajax errors on the site EXCEPT on the page I'm calling refreshActionLinks. Notice, I already have try/catch surrounding my ajax call. why doesn't that work?
thanks
figured it out:
ajax has a settings:
global: false
now my function looks like this:
function refreshActionLinks($row, machineId, packageId) {
try {
var json = JSON.stringify({ packageId: packageId, machineId: machineId, tabType: $("#TabType").val() });
console.log("refreshActionLinks => " + json);
$row.find("td.options div.actionLinks").html("<img src='#Url.Content("~/Content/images/ajax-load2.gif")' />"); // pending
return $.ajax({
url: "#Url.Action("GetActionLinks", "Packages")",
global: false, // disable error pages on failed ajax calls
data: json,
timeout: 50000,
contentType: 'application/json',
type: 'POST',
success: function (data) {
if ($row.length) {
$row.find("td.options div.actionLinks").html(data);
}
}
});
} catch(e) {
// hide icons
$row.find("a.action").remove();
}
}

Categories