Can this old-style ajax call be easily done with jquery? - javascript

I'm working with some pretty old code and the following is being used to monitor session status. If the user is inactive for X minutes (determined by check_session.php), they are logged out.
The server side stuff works fine. Actually, the existing javascript appears to work OK as well, but looks like it needs cleaning up.
Here's the existing javascript:
function checkSessionStatus()
{
session_http.open('GET', '/check_session.php', true);
session_http.onreadystatechange = handleSessionHttpResponse;
session_http.send(null);
}
function handleSessionHttpResponse()
{
if (session_http.readyState == 4)
{
results = session_http.responseText;
if (results == 'inactive')
{
window.location='/logout.php';
document.getElementById('session_divbox').innerHTML = results;
}
}
}
function get_session_HTTPObject()
{
var xml_session_http;
if (!xml_session_http && typeof XMLHttpRequest != 'undefined')
{
try
{
xml_session_http = new XMLHttpRequest();
}
catch (e)
{
xml_session_http = false;
}
}
return xml_session_http;
}
var session_http = get_session_HTTPObject();
function init_page_header()
{
window.setInterval( 'checkSessionStatus();', 30000);
}
This seems incredibly long for what it is doing.
I am still learning jquery and am able to do some basic ajax calls like this one, which places a returned value in a div:
$(document).ready(function()
{
$('#users_online').load('/show_users_online.php');
var refreshId = setInterval(function()
{
$('#users_online').load('/show_users_online.php');
}, 2000);
$.ajaxSetup({ cache: false });
});
The issue with the first bit of code is that it returns a value of 'inactive', which is then acted on by the client (window redirect).
Is it possible to do this in Jquery without winding up with dozens of lines of code? I may already know how to do this and am not seeing the forest for the trees -- some guidance here is appreciated.

Even if its very vampiric question style, should look like
$.get('/check_session.php', function( data ) {
if( data === 'inactive' ) {
window.location='/logout.php';
document.getElementById('session_divbox').innerHTML = data;
}
});

Related

array of callbacks as Promise?

I am working through some old legacy code dealing with network requests using RPC/YUI library. It essentially creates tags to handle network requests. There are no promises for these.Also, because of IE11 support, we cannot use the native Promise object. Our build process does not utilize any NPM dependencies, so we cannot use any babel related polyfills.
There is a bug I am working on to fix that the argument ignoreError gets overwritten each time another function calls the same function....obviously! We have multiple functions calling this network request function library. Sometimes we want to ignore an error, sometimes we do not.
What is the ideal way to store the multiple requests made and their respective error callbacks so the appropriate item is called?
example:
var rpcUrl,
rpcRetries,
rpcIgnoreError;
// main function that sets some globals:
rpc: function(url, retries, ignoreError) {
rpcUrl = url;
rpcRetries = retries;
rpcIgnoreError = ignoreError;
this.doRpc();
},
// calls the YUI library to initialize network script:
doRpc: function() {
YAHOO.util.Get.script(rpcUrl, {
onFailure: function() {
this.callbackError(true);
},
timeout: 55000
});
},
// YUI callback
callbackError: function(retry) {
if (retry && rpcRetries > 0) {
rpcRetries = rpcRetries - 1;
this.doRpc();
} else {
// ** how do i know this error handling is for the script which failed?
if (!rpcIgnoreError) {
this.populateFormStatus(6);
}
}
},
now, we have multiple functions calling rpc() such as:
sendConfig: function() {
this.rpc(urlForEndpoint, 3, true);
},
sendUser: function() {
this.rpc(urlForEndpoint, 3, false);
},
sendWidget: function() {
this.rpc(urlForEndpoint, 3, false);
},
I am concerned making an array of callbacks will not guarantee that each item is handled with its respective handler.
I could do something like create a map constant:
var RPC_ERR_CB = {
sendConfig: false,
sendUser: true,
sendWidget: true
};
// and then in the onFailure callback, I can read the src of the script tag:
...
doRpc: function() {
YAHOO.util.Get.script(rpcUrl, {
onFailure: function() {
var hasCB = Object.keys(RPC_ERR_CB).some(function(item) {
return arguments[0].src.indexOf(RPC_ERR_CB[item]) <= 0;
});
if (hasCB) {
this.callbackError(true);
}
},
timeout: 55000
});
},
Hope this makes sense...THANKS!
You could pass the values into doRpc, then you can pass it to callbackError or handle it in doRpc (like your example code at the end). This will prevent the global variable from changing on you.
If you're not able to use Promises or ES6 Classes, your options become somewhat limited. If at all possible, I would recommend biting the bullet on getting a Babel transpilation process so you can take advantage of newer features without needing to drop IE11 support.
As it is now though, ideally you don't want to track every request in a global variable somewhere. You can handle each transaction independently by creating each request as a self-contained object:
function RpcRequest (url, retries, ignoreError) {
this.url = url
this.retries = retries
this.ignoreError = ignoreError
}
RpcRequest.prototype.send = function() {
YAHOO.util.Get.script(this.url, {
onFailure: function() {
this.callbackError(true);
},
timeout: 55000
});
}
RpcRequest.prototype.callbackError = function(retry) {
if (retry && this.retries > 0) {
this.retries = this.retries - 1;
this.send();
} else {
if (!this.ignoreError) {
// ...
}
}
}
// Somewhere else, initiate a request
var requestOne = new RpcRequest("http://blah", 3, false)
requestOne.send()
Something I noted when looking over your code: the code that's creating the request has no idea whether the request succeeded or not. And when you have an error, the calling context doesn't know anything about that error. I took a look at the library you mentioned, and it does appear to have some context that you can pass along.
If I were to rewrite this a little bit, I'd do something like this to bubble the error up to your calling context:
RpcRequest.prototype.send = function(callback) {
YAHOO.util.Get.script(this.url, {
onFailure: function(context) {
if( this.ignoreError ) {
context.ignoredError = true
callback(null, context);
return;
}
var retError = new Error('Failure doing something!');
retError.context = context;
callback(retError);
},
onSuccess: function(context) {
callback(null, context);
},
timeout: 55000
});
}
// Somewhere else in the code...
sendWidget: function() {
var request = new RpcRequest(urlForEndpoint, 3, false)
request.send(function(err, result) {
if( err ) {
console.error('Failed at doing a widget thing:', err.context);
// maybe even:
// throw err;
return;
}
if( result.ignoredError ) {
console.warn('Ignored an error on the widget thing:', result);
return;
}
console.log('Success on the widget thing!', result);
})
}

Create custom event, like ionicPlatform.ready() or document.ready()

I have an Ionic app in which I use a database. I want to fill this database with the contents of a file.
This part I got working. I want to create a DB.ready() event, much like the $ionicPlatform.ready() or document.ready(), as I need to wait until the database is loaded until I query it.
I am fairly new to Ionic, and to the concept of Promises, so it might be something simple.
I've gotten it to work in Android, but iOS keeps returning an error in the query with "someTablename does not exist". I've placed multiple console.log(), and according to those everything is fine.
Could anyone tell me which part I did incorrect, or another method if that is more common in this situation (again, I'm new, so don't know what is common)?
I expected to get "query" logged every query, but it doesn't do that, is that significant?
// L35_DB - Databaseclass for apps
.factory('L35_DB', ['$ionicPlatform','$cordovaFile','$cordovaSQLite', function($ionicPlatform, $cordovaFile,$cordovaSQLite) {
var L35_DB = {db_start : false};
//-------------------------------------
DB_READY = new Promise(function(resolve,reject){
console.log("query");
if( L35_DB.db_start ){console.log("b"); resolve("Stuff worked!"); }
else{
var filename='fileWithDB.db';
$ionicPlatform.ready(function() {
if( window.cordova ){
return window.plugins.sqlDB.copy(filename, 0,
function(info){ loadDB(filename).then( function(){ console.log("First load", info); resolve("DB loaded?"); }) },
function(info){ loadDB(filename).then( function(){ console.log("Other loads", info); resolve("DB loaded?"); }) }
);
}
});
}
});
//-------------------------------------
// Load the file
function loadDB(filename){
var loading = new Promise(function(resolve,reject){
db = window.sqlitePlugin.openDatabase(
{name: filename, location: 'default'},
function(){
console.log("loadDB success"); // <--- fired
L35_DB.db_start = true; // true, so next call we don't do all this
resolve("DB ready loading");
},
function(err){ reject(err);}
);
});
return loading;
}
//-------------------------------------
// Query -
var _query = function(query,values){
if( !L35_DB.db_start ){
console.error("DB not init");
return false;
}
else if( window.cordova ){
values = values || [];
var actualQuery = new Promise(function(resolve,reject){
db.executeSql(query, values, resolve, reject);
})
return actualQuery;
}
}
//-------------------------------------
return {
query : _query
};
}])
Throughout my app I do:
DB_READY.then(function () {
L35_DB.query("SELECT * FROM systems").then(function (result) {
// Something something something darkside
})
})
After a lot of testing and digging, turns out window.plugins.sqlDB.copy() was the culprit.
The 2nd value, location, can be changed. It defaults to 0, but for iOS it has to be 2. After this change, everything work exactly as expected.
This function should preload the database for Android and iOS, assumed a bit too early it actually did.

Nested AJAX call not working

I'm having trouble getting a nested AJAX call to work properly. All I want is to have the inner AJAX call executed if and after the outer AJAX call completed successfully.
var diningHours = $("#diningHours");
var facStaffDiningData = $("#facStaffDiningData");
var diningCommonsData = $("#diningCommonsData");
if($.trim(diningHours.html()).length == 0) {
var season;
//This call executes fine (tested it with console logging)
$.get("data/dining-hours.php", {summer: "check"}, function(seasonData, seasonStatus) {
if(seasonStatus == "success") {
season = seasonData;
//This is the call that isn't being executed
$.get("data/dining-hours.php", function(hoursData, hoursStatus) {
if(hoursStatus == "success") {
var hours = $(hoursData).find("hours dining");
var html = hoursFeed(hours, season);
diningHours.append(html).collapsibleset("refresh");
}
});
}
});
}
Am I doing something wrong?
I'd try something like this:
var diningHours = $("#diningHours"),
facStaffDiningData = $("#facStaffDiningData"),
diningCommonsData = $("#diningCommonsData");
if(!$.trim(diningHours.html()).length) {
var XHR = $.get("data/dining-hours.php", {summer: "check"});
XHR.success(function(seasonData) {
var season = seasonData,
XHR2 = $.get("data/dining-hours.php");
XHR2.success(function(hoursData) {
var hours = $(hoursData).find("hours dining"),
html = hoursFeed(hours, season);
diningHours.append(html).collapsibleset("refresh");
});
});
}​
The question is, what exactly is hours dining, and how do you expect the find() function to find it ?
I think seasonStatus is redundant, because the callback will be executed on success.
This should works
var season;
//This call executes fine (tested it with console logging)
$.get("data/dining-hours.php", {summer: "check"}, function(season, seasonStatus) {
console.log('CB1',season);
$.get("data/dining-hours.php", function(hoursData) {
console.log('CB2',hoursData);
var hours = $(hoursData).find("hours dining");
var html = hoursFeed(hours, season);
diningHours.append(html).collapsibleset("refresh");
});
}
});
Digging deeper into the issue I found the true source of my problem. The XML document had a bunch of encoding errors (there were things like reserved and copyright symbols in with the data). Removing these and replacing them with the correct entities fixed the problem. My original code that I thought was the issue now works perfectly fine.

How to extract partial JSON from API response?

Load when the browser is open
Thats my previous question related to this topic.
My problem is that the server api i use has added a new item to the list and as i stated in the previous question im not very skilled with API's or jQuery, therefore i would like to know what can you recomend me to read about this and also pratical solutions. I need to make it so the field that the js uses is only {"name":"Arthas","slug":"arthas","build":"12340","status":1} and not the rest.
Many thanks in advance.
This is the api -> http://api.neverendless-wow.com/server-status
{"servers":[{"name":"Arthas","slug":"arthas","build":"12340","status":1},{"name":"Deathwing","slug":"deathwing","build":"13623","status":1}],"alerts":[]}
This is my current js
function checkStatus()
{
jQuery.getJSON("http://api.neverendless-wow.com/server-status",function(data){
if (data.status == '1') {jQuery('#ServStat').addClass('online').removeClass('offline').attr('label','Online');}
else {jQuery('#ServStat').addClass('offline').removeClass('online').attr('label','Offline');}});
}
checkStatus();
{
setInterval(changeState, 300000)
}
You need to use data as array (data[0]) and hence your code will be as follows:
function checkStatus()
{
jQuery.getJSON("http://api.neverendless-wow.com/server-status",function(data){
if (data.servers[0].status == '1') {
jQuery('#ServStat').addClass('online').removeClass('offline').attr('label','Online');
}
else {
jQuery('#ServStat').addClass('offline').removeClass('online').attr('label','Offline');
}
});
}
checkStatus();
{
setInterval(changeState, 300000)
}
I would probably go with something like this:
// check server status
function checkStatus()
{
$.getJSON(server_url, function(data) {
// reset
var mode = "Offline";
$('.status').removeClass('online').addClass('offline');
// is available?
if (data !== null && data.servers !== null && data.servers[0].status === 1) {
mode = "Online";
$('.status').removeClass('offline').addClass('online');
}
// Extract data from received JSON string is exists
extractData(data);
// set needed attributes
$('.status')
.attr('label', mode)
.text('Servers are ' + mode);
});
}
Live demo available on JsBin

JavaScript: What would cause setInterval to stop firing?

I am writing a chat AJAX app. Randomly, in FF 3.5.9, setInterval() seems to stop firing. I don't have clearInterval() anywhere in my code. What could be causing this to happen?
$(document).ready(function () {
$("#no-js-warning").empty();
messageRefresher = new MessageRefresher(0);
setInterval($.proxy(messageRefresher, "refresh"), 2000);
});
function notifyInRoom(user) {
$.getJSON('API/users_in_room', { room_id: $.getUrlVar('key'), username: user }, function (users) {
if (!$.isEmptyObject(users)) {
$("#users").empty();
$.each(users, function (index, username) {
var newChild = sprintf("<li>%s</li>", username);
$("#users").append(newChild);
});
}
else {
$("#users-loading-msg").text("No one is in this room.");
}
});
}
function MessageRefresher(latest_mid) {
this._latest_mid = latest_mid;
}
MessageRefresher.prototype.refresh = function () {
notifyInRoom($("#user-name").val());
var refresher = this;
$.getJSON('API/read_messages', { room_id: $.getUrlVar('key'), mid: refresher._latest_mid }, function (messages) {
if (! (messages == null || $.isEmptyObject(messages[0]))) { // messages will always be at least [[], [], 0]
$("#messages-loading-msg").hide();
for (var i = 0; i < messages[0].length; i++) {
var newChild = sprintf('<li><span class="username">%s:</span> %s</li>', messages[1][i], messages[0][i]);
$("#messages").append(newChild);
}
refresher._latest_mid = messages[2];
setUserBlockClass();
}
else {
$("#messages-loading-msg").text("No messages here. Say anything...");
}
});
}
// Give the end-user-block class to the appropriate messages
// eg, those where the next message is by a different user
function setUserBlockClass() {
$("#messages li").each(function (index) {
if ($(this).children(".username").text() != $(this).next().children(".username").text()) {
$(this).addClass("end-user-block");
}
});
}
I checked the most recent responses in Firebug, and it was the same responses that had been sent earlier. (So, it's not like an unusual response caused a crash.)
If I refresh the page, the calls resume.
I'm setting breakpoints in Firebug while I develop, then unsetting them and hitting "continue". Is there any chance that this is causing the problem? UPDATE: With more testing, this seems like it might be the issue.
I'm also using the service in another browser, and the calls continue fine for it.
I'm seeing setInterval getting stopped when I debug with Firebug. Assume it's a timing/interrupt thing as it works fine as long as I'm not stepping over breakpoints.
One thing to check that I just ran into was that if you are checking whether setInterval works with something like:
console.log("X");
Firebug will only display the 'X' one time. Firebug appears to refuse to log the same text twice. However, testing in the Chrome console worked fine.
When I changed my test code to:
console.log(new Date());
Firebug gave me the results I expected.

Categories