I'm currently developing a tumblr theme and have built a jQuery JSON thingamabob that uses the Tumblr API to do the following:
The user would click on the "post type" link (e.g. Video Posts), at which stage jQuery would use JSON to grab all the posts that's related to that type and then dynamically display them in a designated area.
Now everything works absolutely peachy, except that with Tumblr being Tumblr and their servers taking a knock every now and then, the Tumblr API thingy is sometimes offline. Now I can't foresee when this function will be down, which is why I want to display some generic error message if JSON (for whatever reason) was unable to load the post.
You'll see I've already written some code to show an error message when jQuery can't find any posts related to that post type BUT it doesn't cover any server errors. Note: I sometimes get this error:
Failed to load resource: the server responded with a status of 503 (Service Temporarily Unavailable)
It is for this 503 Error message that I need to write some code, but I'm slightly clueless :)
Here's the jQuery JSON code:
$('ul.right li').find('a').click(function() {
var postType = this.className;
var count = 0;
byCategory(postType);
return false;
function byCategory(postType, callback) {
$.getJSON('{URL}/api/read/json?type=' + postType + '&callback=?', function(data) {
var article = [];
$.each(data.posts, function(i, item) {
// i = index
// item = data for a particular post
switch(item.type) {
case 'photo':
article[i] = '<div class="post_wrap"><div class="photo" style="padding-bottom:5px;">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/XSTldh6ds/photo_icon.png" alt="type_icon"/></a>'
+ '<a href="' + item.url + '" title="{Title}"><img src="'
+ item['photo-url-500']
+ '"alt="image" /></a></div></div>';
count = 1;
break;
case 'video':
article[i] = '<div class="post_wrap"><div class="video" style="padding-bottom:5px;">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon">'
+ '<img src="http://static.tumblr.com/ewjv7ap/nuSldhclv/video_icon.png" alt="type_icon"/></a>'
+ '<span style="margin: auto;">'
+ item['video-player']
+ '</span>'
+ '</div></div>';
count = 1;
break;
case 'audio':
if (use_IE == true) {
article[i] = '<div class="post_wrap"><div class="regular">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/R50ldh5uj/audio_icon.png" alt="type_icon"/></a>'
+ '<h3><a href="'
+ item.url
+ '">'
+ item['id3-artist']
+' - '
+ item['id3-title']
+ '</a></h3>'
+ '</div></div>';
} else {
article[i] = '<div class="post_wrap"><div class="regular">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/R50ldh5uj/audio_icon.png" alt="type_icon"/></a>'
+ '<h3><a href="'
+ item.url
+ '">'
+ item['id3-artist']
+' - '
+ item['id3-title']
+ '</a></h3><div class="player">'
+ item['audio-player']
+ '</div>'
+ '</div></div>';
};
count = 1;
break;
case 'regular':
article[i] = '<div class="post_wrap"><div class="regular">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/dwxldhck1/regular_icon.png" alt="type_icon"/></a><h3><a href="'
+ item.url
+ '">'
+ item['regular-title']
+ '</a></h3><div class="description_container">'
+ item['regular-body']
+ '</div></div></div>';
count = 1;
break;
case 'quote':
article[i] = '<div class="post_wrap"><div class="quote">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/loEldhcpr/quote_icon.png" alt="type_icon"/></a><blockquote><h3><a href="' + item.url + '" title="{Title}">'
+ item['quote-text']
+ '</a></h3></blockquote><cite>- '
+ item['quote-source']
+ '</cite></div></div>';
count = 1;
break;
case 'conversation':
article[i] = '<div class="post_wrap"><div class="chat">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/MVuldhcth/conversation_icon.png" alt="type_icon"/></a><h3><a href="'
+ item.url
+ '">'
+ item['conversation-title']
+ '</a></h3></div></div>';
count = 1;
break;
case 'link':
article[i] = '<div class="post_wrap"><div class="link">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/EQGldhc30/link_icon.png" alt="type_icon"/></a><h3><a href="'
+ item['link-url']
+ '" target="_blank">'
+ item['link-text']
+ '</a></h3></div></div>';
count = 1;
break;
default:
alert('No Entries Found.');
};
}) // end each
if (!(count == 0)) {
$('#content_right')
.hide('fast')
.html('<div class="first_div"><span class="left_corner"></span><span class="right_corner"></span><h2>Displaying '
+ postType
+ ' Posts Only</h2></div>'
+ article.join(''))
.slideDown('fast')
} else {
$('#content_right')
.hide('fast')
.html('<div class="first_div"><span class="left_corner"></span><span class="right_corner"></span><h2>Hmmm, currently there are no '
+ postType
+ ' posts to display</h2></div>')
.slideDown('fast')
}
// end getJSON
}); // end byCategory
}
});
If you'd like to see the demo in action, check out Elegantem but do note that everything might work absolutely fine for you (or not), depending on Tumblr's temperament.
$('ul.right li').find('a').click(function() {
var postType = this.className;
var count = 0;
byCategory(postType);
return false;
function byCategory(postType, callback) {
$.getJSON('{URL}/api/read/json?type=' + postType + '&callback=?', function(data, textStatus, xhr) { // main callback function
if(xhr.status == 500 || xhr.status == 404 || xhr.status == 503) {
yourErrorHandler(data, textStatus, xhr); // success
} else {
yourCallbackToRunIfSuccessful(data); // failed
}
}
);
function yourCallbackToRunIfSuccessful(data) {
var article = [];
$.each(data.posts, function(i, item) {
// i = index
// item = data for a particular post
switch(item.type) {
case 'photo':
article[i] = '<div class="post_wrap"><div class="photo" style="padding-bottom:5px;">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/XSTldh6ds/photo_icon.png" alt="type_icon"/></a>'
+ '<a href="' + item.url + '" title="{Title}"><img src="'
+ item['photo-url-500']
+ '"alt="image" /></a></div></div>';
count = 1;
break;
case 'video':
article[i] = '<div class="post_wrap"><div class="video" style="padding-bottom:5px;">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon">'
+ '<img src="http://static.tumblr.com/ewjv7ap/nuSldhclv/video_icon.png" alt="type_icon"/></a>'
+ '<span style="margin: auto;">'
+ item['video-player']
+ '</span>'
+ '</div></div>';
count = 1;
break;
case 'audio':
if (use_IE == true) {
article[i] = '<div class="post_wrap"><div class="regular">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/R50ldh5uj/audio_icon.png" alt="type_icon"/></a>'
+ '<h3><a href="'
+ item.url
+ '">'
+ item['id3-artist']
+' - '
+ item['id3-title']
+ '</a></h3>'
+ '</div></div>';
} else {
article[i] = '<div class="post_wrap"><div class="regular">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/R50ldh5uj/audio_icon.png" alt="type_icon"/></a>'
+ '<h3><a href="'
+ item.url
+ '">'
+ item['id3-artist']
+' - '
+ item['id3-title']
+ '</a></h3><div class="player">'
+ item['audio-player']
+ '</div>'
+ '</div></div>';
};
count = 1;
break;
case 'regular':
article[i] = '<div class="post_wrap"><div class="regular">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/dwxldhck1/regular_icon.png" alt="type_icon"/></a><h3><a href="'
+ item.url
+ '">'
+ item['regular-title']
+ '</a></h3><div class="description_container">'
+ item['regular-body']
+ '</div></div></div>';
count = 1;
break;
case 'quote':
article[i] = '<div class="post_wrap"><div class="quote">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/loEldhcpr/quote_icon.png" alt="type_icon"/></a><blockquote><h3><a href="' + item.url + '" title="{Title}">'
+ item['quote-text']
+ '</a></h3></blockquote><cite>- '
+ item['quote-source']
+ '</cite></div></div>';
count = 1;
break;
case 'conversation':
article[i] = '<div class="post_wrap"><div class="chat">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/MVuldhcth/conversation_icon.png" alt="type_icon"/></a><h3><a href="'
+ item.url
+ '">'
+ item['conversation-title']
+ '</a></h3></div></div>';
count = 1;
break;
case 'link':
article[i] = '<div class="post_wrap"><div class="link">'
+ '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/EQGldhc30/link_icon.png" alt="type_icon"/></a><h3><a href="'
+ item['link-url']
+ '" target="_blank">'
+ item['link-text']
+ '</a></h3></div></div>';
count = 1;
break;
default:
alert('No Entries Found.');
};
}) // end each
if (!(count == 0)) {
$('#content_right')
.hide('fast')
.html('<div class="first_div"><span class="left_corner"></span><span class="right_corner"></span><h2>Displaying '
+ postType
+ ' Posts Only</h2></div>'
+ article.join(''))
.slideDown('fast')
} else {
$('#content_right')
.hide('fast')
.html('<div class="first_div"><span class="left_corner"></span><span class="right_corner"></span><h2>Hmmm, currently there are no '
+ postType
+ ' posts to display</h2></div>')
.slideDown('fast')
}
// end getJSON
}; // end byCategory
function yourErrorHandler(data,textStatus,xhr) {
alert("Server returned status code " + xhr.status + ". Try again later.");
}
}
});
Your callback actually takes 2 other parameters you're not showing:
$.getJSON('{URL}/api/read/json?type=' + postType +
'&callback=?',
function(data, textStatus, xhr) { // main callback function
if(xhr.status == 500 || xhr.status == 404 || xhr.status == 503) {
yourErrorHandler(data, textStatus, xhr); // success
} else {
yourCallbackToRunIfSuccessful(data); // failed
}
}
);
// your original code, but wrapped up in it's own function definition
function yourCallbackToRunIfSuccessful(data) {
var article = [];
$.each(data.posts, function(i, item) {
// i = index
// item = data for a particular post
switch(item.type) {
case 'photo':
...
...
}
function yourErrorHandler(data,textStatus,xhr) {
alert("Server returned status code " + xhr.status + ". Try again later.");
}
You can use the xhr object to check the status of the raw XMLHttpRequest object. If you get a 404, 503, 500, etc then you can display your error message or run your alternate function.
http://api.jquery.com/jQuery.ajax
Also, if you don't already have Firebug for Firefox, I'd highly recommend it for JavaScript debugging: http://getfirebug.com/
UPDATE:
The getJSON JQuery AJAX wrapper does not have an error callback handler. Instead, you'll need to use the regular JQuery AJAX handler to make your JSON request:
jQuery.ajax({
type: "GET",
url: '{URL}/api/read/json?type=' + postType +
'&callback=?',
dataType: "json",
success: function(results){
console.info("Success!");
yourCallbackToRunIfSuccessful(results);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
alert("Error");
yourErrorHandler(XMLHttpRequest, textStatus, errorThrown);
}
});
It's important to note that this is NOT JSONP. This means you cannot make cross-domain requests using this function.
If you're relying on JSONP using my original answer, then you'll need to implement a solution whereby you set a setInterval event to poll a value that will be changed in your callback. More details can be found here:
http://groups.google.com/group/jquery-dev/browse_thread/thread/73ca6be8071479fb