Earlier today I noticed an entry on the PhoneGap forums from a user asking about an RSS reader. I thought I'd whip one up using PhoneGap and jQuery Mobile and see what it took. Here's what I came up, and as always, feel free to rip apart the code and write it better. I'll warn folks that I only wrote the code to support RSS2, not ATOM, but in theory, it should be possible without too much additional work. (You would simply look at the metadata, note it, and change how you get data.)
I began by creating a new PhoneGap project. I strongly recommend reading my entry from earlier today about the nice Eclipse PhoneGap plugin to make it quicker to setup your projects. I began by adding code to handle getting the RSS code. First, I setup two simple variables people could tweak:
//EDIT THESE LINES
//Title of the blog
var TITLE = "ColdFusion Jedi";
//RSS url
var RSS = "http://feedproxy.google.com/RaymondCamdensColdfusionBlog";
My code listens for my initial page to load. When this happens, I want to get the XML from the feed and work with it. Here's that snippet.
$.get(RSS, {}, function(res, code) {
var xml = $(res);
var items = xml.find("item");
$.each(items, function(i, v) {
entry = {
title:$(v).find("title").text(),
link:$(v).find("link").text(),
description:$.trim($(v).find("description").text())
};
entries.push(entry);
});
As a reminder, AJAX code in PhoneGap applications are not restricted by normal remote domain rules. I can easily open up the remote XML and parse it. Where did entries come from? Well this is where things get slightly complex. I'm going to store the parsed RSS in a global array called entries (hence the push to add things to the end). This will allow me to dynamically display the pages. But first, let's render out the list. My home page already has a blank list just for this purpose:
<div data-role="content">
<ul id="linksList" data-role="listview" data-inset="true"></ul>
</div>
So my handler can simply append to it....
//now draw the list
var s = '';
$.each(entries, function(i, v) {
s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>';
});
$("#linksList").append(s);
$("#linksList").listview("refresh");
Note two things here. First, every single link will be going to a new jQuery Mobile page, contentPage. But I store the ID of the item in a data attribute. Also note the use listview("refresh"). This tells jQuery Mobile to add unicorn magic prettiness to HTML I've added in the list. Serious - Unicorn Magic Prettiness is the official term.
Ok, so what's going on with the content page? I created it as a blank page, like so:
<div data-role="page" id="contentPage">
<div data-role="header">
<a href="#mainPage" data-rel="back">Home</a>
<h1></h1>
</div>
<div data-role="content" id="entryText">
</div>
</div>
And I've got a JavaScript click handler that notices the clicks and populates the data. First, the event listener for the link:
//listen for detail links
$(".contentLink").live("click", function() {
selectedEntry = $(this).data("entryid");
});
And then the page displayer...
//Listen for the content page to load
$("#contentPage").live("pageshow", function(prepage) {
//Set the title
$("h1", this).text(entries[selectedEntry].title);
var contentHTML = "";
contentHTML += entries[selectedEntry].description;
contentHTML += '<p/><a href="'+entries[selectedEntry].link + '">Read Entry on Site</a>';
$("#entryText",this).html(contentHTML);
});
Pretty simple, right? (I should point out jQuery Mobile does support completely virtualized pages too. ) Here's a quick screen shot...

And another one...

And finally, the complete code. If anyone wants the actual APK for this, just ask. The home page first:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" />
<script src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
<script src="main.js"></script>
<script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="mainPage">
<div data-role="header">
<h1></h1>
</div>
<div data-role="content">
<ul id="linksList" data-role="listview" data-inset="true"></ul>
</div>
<div data-role="footer">
<h4>SimpleBlog by Raymond Camden</h4>
</div>
</div>
<div data-role="page" id="contentPage">
<div data-role="header">
<a href="#mainPage" data-rel="back">Home</a>
<h1></h1>
</div>
<div data-role="content" id="entryText">
</div>
</div>
</body>
</html>
And the main.js file:
$(document).ready(function() {
//EDIT THESE LINES
//Title of the blog
var TITLE = "ColdFusion Jedi";
//RSS url
var RSS = "http://feedproxy.google.com/RaymondCamdensColdfusionBlog";
//Stores entries
var entries = [];
var selectedEntry = "";
//listen for detail links
$(".contentLink").live("click", function() {
selectedEntry = $(this).data("entryid");
});
//Listen for main page
$("#mainPage").live("pageinit", function() {
//Set the title
$("h1", this).text(TITLE);
$.get(RSS, {}, function(res, code) {
var xml = $(res);
var items = xml.find("item");
$.each(items, function(i, v) {
entry = {
title:$(v).find("title").text(),
link:$(v).find("link").text(),
description:$.trim($(v).find("description").text())
};
entries.push(entry);
});
//now draw the list
var s = '';
$.each(entries, function(i, v) {
s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>';
});
$("#linksList").append(s);
$("#linksList").listview("refresh");
});
});
//Listen for the content page to load
$("#contentPage").live("pageshow", function(prepage) {
//Set the title
$("h1", this).text(entries[selectedEntry].title);
var contentHTML = "";
contentHTML += entries[selectedEntry].description;
contentHTML += '<p/><a href="'+entries[selectedEntry].link + '">Read Entry on Site</a>';
$("#entryText",this).html(contentHTML);
});
});
Archived Comments
Well, thank God for "Unicorn Magic Prettiness", $("#linksList").listview("refresh"); made me look more closely at the docs to see if this was also available for form elements, which of course it was. So happily I can get rid of the hacky way I was accomplishing this before (initing multiple plugins on all the dynamic elements I was adding).
Funny how when you read documentation you can miss things you aren't looking for...
Yep - I'm reading stuff as I write my book and discovering all kinds of little things I missed.
I should point out that the latest jQuery build is 1.6.4.
And? Sorry - am I missing something?
Nice work, as usual, Ray. Have you given any thought to add search and paging?
Henry
Search wouldn't be possible unless you knew the search URL for the remote blog, and even then, the remote blog would need to provide an API to search so that you can get results in JSON (or some other format). Paging also wouldn't make sense because most RSS feeds don't allow for it - they just return the last N entries.
Thank you for this great script. I am trying to enhance it a bit, there is a delay when i like to the page with this code, so you get the header, and a blank page until the LI rss items load....Can you help me add the jquery mobile loading screen while the items are populated.
For some reason adding these did not work for me
// show
$.mobile.pageLoading();
// hide
$.mobile.pageLoading(true);
Thank you
Well, I'd probably do this.
1) In my home page, the first div with data-role=content, I'd add a new inner div above the empty ul. Something like: <div id="preloading">Please stand by...</div>
2) When I get my crap back and before I add the items, then just do $("#preloading").html("")
Thanks for the tip Raymond!
I added the jquery spinning wheel/loading pop up for the stories. Looks pretty nice now. Also changed the external story link to open with browser with - target="_webapp"
Here is my updated script
<script>
//show loader
var showLoader = function () {
$('.ui-loader').css('display', 'block');
}
//hide loader
var hideLoader = function () {
$('.ui-loader').css('display', 'none');
}
$(document).ready(function() {
// alert('test');
//EDIT THESE LINES
//Title of the blog
var TITLE = "News";
//RSS url
var RSS = "news.xml";
//Stores entries
var entries = [];
var selectedEntry = "";
//listen for detail links
$(".contentLink").live("click", function() {
selectedEntry = $(this).data("entryid");
});
//Listen for main page
$("#mainPage").live("pageinit", function() {
showLoader(); //Set the title
$("h1", this).text(TITLE);
$.get(RSS, {}, function(res, code) {
var xml = $(res);
var items = xml.find("item");
$.each(items, function(i, v) {
entry = {
title:$(v).find("title").text(),
link:$(v).find("link").text(),
description:$.trim($(v).find("description").text())
};
entries.push(entry);
hideLoader();
});
//now draw the list
var s = '';
$.each(entries, function(i, v) {
s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>';
});
$("#linksList").append(s);
$("#linksList").listview("refresh");
});
});
//Listen for the content page to load
$("#contentPage").live("pageshow", function(prepage) {
//Set the title
$("h1", this).text(entries[selectedEntry].title);
var contentHTML = "";
contentHTML += entries[selectedEntry].description;
contentHTML += '<p/><a target="_webapp" href="'+entries[selectedEntry].link + '">Read Entry on Site</a>';
$("#entryText",this).html(contentHTML);
});
});
</script>
Ned some help...so i am trying to open up a news feed page from the main page, to get the jquery mobile transition effect, i am calling it with
$.mobile.changePage( 'news.html', { transition: 'slide'} );"
however when the page slides, i got the blank page, that is not populated wit hthe news stories from the javascript.....any ideas? i would think the document.ready event should make sure its populated after page is loaded? thank you
Well I'd need to see more. When you load a page like that, if it hasn't been injected in the DOM yet then it will be blank. (Well not blank, but whatever is in news.html.) You can't add stuff to that page until _after_ it has been loaded.
Is this code specifically for android. I am trying to apply the code in Xcode with phonegap with no success. Is there any major changes i would have to make.
Thanks
Nope, it should work. I've never done the Phonegap process on iOS, but if you start your project according to their docs, then use my code, it should work. If not, you need to provide me a bit more detail on what is going wrong.
I am having no luck with it. The main.js does not seem to be responding. I have set an alert within the main.js and it won't alert. here is the following html code and main.js-
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="jq/jquery.mobile-1.0b1.min.css">
<script type="text/javascript" charset="utf-8" src="phonegap.0.9.6.min.js"></script>
<script type="text/javascript" charset="utf-8" src="jq/jqueryCombined.js"></script>
<script type="text/javascript" charset="utf-8" src="main.js"></script>
</head>
<body>
<div data-role="page" id="mainPage">
<div data-role="header">
<h1></h1>
</div>
<div data-role="content">
<ul id="linksList" data-role="listview" data-inset="true"></ul>
</div>
</div>
<div data-role="page" id="contentPage">
<div data-role="header">
<a href="#mainPage" data-rel="back">Home</a>
<h1></h1>
</div>
<div data-role="content" id="entryText">
</div>
</div>
</body>
</html>
main.js
var showLoader = function () {
$('.ui-loader').css('display', 'block');
}
alert("test");
//hide loader
var hideLoader = function () {
$('.ui-loader').css('display', 'none');
}
alert("test");
$(document).ready(function() {
alert("test");
//EDIT THESE LINES
//Title of the blog
var TITLE = "News";
//RSS url
var RSS = "news.xml";
//Stores entries
var entries = [];
var selectedEntry = "";
//listen for detail links
$(".contentLink").live("click", function() {
selectedEntry = $(this).data("entryid");
});
//Listen for main page
$("#mainPage").live("pageinit", function() {
showLoader(); //Set the title
$("h1", this).text(TITLE);
$.get(RSS, {}, function(res, code) {
var xml = $(res);
var items = xml.find("item");
$.each(items, function(i, v) {
entry = {
title:$(v).find("title").text(),
link:$(v).find("link").text(),
description:$.trim($(v).find("description").text())
};
entries.push(entry);
hideLoader();
});
//now draw the list
var s = '';
$.each(entries, function(i, v) {
s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>';
});
$("#linksList").append(s);
$("#linksList").listview("refresh");
});
});
//Listen for the content page to load
$("#contentPage").live("pageshow", function(prepage) {
//Set the title
$("h1", this).text(entries[selectedEntry].title);
var contentHTML = "";
contentHTML += entries[selectedEntry].description;
contentHTML += '<p/><a target="_webapp" href="'+entries[selectedEntry].link + '">Read Entry on Site</a>';
$("#entryText",this).html(contentHTML);
});
});
Ugh, in the future, please, _pretty please_, use Pastebin for code snippets.
Not sure what to suggest to you. That alert should fire. I'd ensure it is in the same folder as the index.html file at minimum.
Hi Raymond,
This is amazing! It works perfect on the iPhone too :)
I was wondering, would this support RSS images too?
The code I have now doesn't look for it. But you could modify it quickly enough.
Thanks for the quick response.
My JS knowledge is pretty poor, but I'm learning :)
This is a great way to have an RSS reader w/o he use of PHP thanks for writing the article!
I am using this code to link to a Youtube channel's rss feed. It works well but I would like to have the user click on the headline and get sent directly to the link instead being sent to the #contentpage. Is that possible? Thanks for any info
Mike
Just change this:
s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>';
Get rid of the class, the data-entryid, and just add url="X" where X is v.... one sec. link. Yeah, should be v.link.
Hey Raymond,
I followed every direction but the last one, I was a little confusing; what did you mean by "just add url="X" where X is v.... one sec. link. Yeah, should be v.link."
This is what I got so far, I think its really close I just need one more thing to fix it.. check it out if you have the time.
http://jsfiddle.net/lamike/...
Thanks a lot,
Mike
So - you got the link out of the XML, but you didn't use it when rendering the entry data.
var s = '';
$.each(entries, function(i, v) {
s += '<li><a href="#contentPage"'+i+'">' + v.title + '</a></li>';
});
Change the link:
s += '<li><a href="'+v.link+'">'+v.title+'</a></li>';
Watch out for typos there.
I'm trying to put some new tags but my app don't show this!
I try with new tags like "<test>" but with [...] find.(test).text() don't show anything!!
The XML file is generated by a PHP and is validated by W3. Anybody can help me? Thanks! :)
You would need to share a bit more code. If you do so, please use pastebin.
No way, I solved correctly this problem :)
But there is a new problem...
I need to know how I can update or remove saved data in device. If the app have been show XML data, if you close the app and update the XML file with new information in the server and open again the app you can't see the new info... because the data was saved in device like temporary files.
If you go to the app list and clean the saved data you can see the new XML info.
Is there any solution for this?
Sorry for my bad english... :P
What you are seeing is simply the app being resumed. You can listen for resume events in PhoneGap and simply refetch the data. Or, you can also provide a Reload type button in the app so users can refresh it themselves. Or both. ;)
Raymond,
I got the rss feed working about a week on an IPhone app with phonegap and sent it out for testing this week. But today all the apps rss feeds are failing and I dont know why. They were all working fine up to yesterday. The simulator is failing to run the rss feed also.
Just wondering if you would have an idea why this would be happening. Has there been a change in the code of the scripts src or something???
Any advice would be appreciated
Simply add an error handler to the code. Mine example does not have that, and it is a mistake. I can help you with this, but not till Monday - going out of town. If you can't wait, go to jQuery's site and look at how they handle errors for Ajax calls.
And thank you for bringing this up. I was remis in not supporting that immediately. I apologize!
Ok, got a simple example working - will post an update tomorrow.
Hi, raymond, thanks for the tutorial..
I have followed the tutorial well, but I have several question.
1. Everytime I choose one of the rss feed, and then I press the back button, the application load some more feeds.
Example:
The first time application start,
the lists is just:
-A
-B,
but when I choose one of them, and press back to the list, it will be,
-A
-B
-A
-B
How to solve this problem?
2. How can I get image from the rss file in javascript?
Thanks.. :)
I fixed that too (see earlier comment about error handling). The quick fix for you is to simply add entries=[] into the get() callback. Or just wait till later today - I'll be blogging it.
Hey guys - please see my follow up here:
http://www.raymondcamden.co...
Oh man you did a very fantastic job. I am very new in Android development and your article helped me out.
Thank you!
can i get the source code for above app pls???
It is in the blog entry.
Superb article thnks...
Hi,
I am trying your example but it throws the following error when I try to load the page in the Emulator:
XMLHttpRequest cannot load http://127.0.0.1:44104/[some-GUID]. Origin null is not allowed by Access-Control-Allow-Origin
The error is thrown by the following line in the code:
$("#mainPage").live("pageinit", function() { ...
Do you have any idea what the solution could be?
I am using Android 4.1 emulator for testing.
Sorry - no idea. I've never seen that before. Have you gotten other PhoneGap apps to work?
I was having some issues with other Phonegap/JQuery apps but now those are working. Still trying to run your app though.
How can I combine two or more feeds . As for single feed it is working fine. But How to combine more than one feed for it.
Please suggest .
Thanks
Soumavo
First, I'd recommend reading the latest entry in this 'series' (yes, it is a series now):
http://www.raymondcamden.co...
I switched to using Google's Feed API to handle parsing the RSS. Unfortunately, it only allows for one feed at a time.
What you would want to do is make use of something like jQuery Deferreds to handle firing N requests and waiting for them to all to finish.
Next - you would combine the data into one array.
Finally - you would want to sort them by date.
hi i 've started a rss reader app with phonegap. i have 2 questions what happens when the local storage is full?
i don't want the app to re download all news everytime hox can i make it download only the new ones?
If you fill up LS, you will get an error. For deep storage I'd use something like WebSQL.
Hi..I would say, this is a great tutorial, however, the feed does not work when I try it in my android device. There are no feed shown though my device already connected to internet. My device is android 4.0.
When I test it in eclipse and my laptop browser, it works fine..
You may want to ensure the URL for the feed is whitelisted. See the docs: http://cordova.apache.org/d...
Thank you. It works!! After I add the permission and all I have to do is make sure my device is connected to facebook as I want the feed to fetch my facebook news feed :)
It doesn't work with me
I only get a blank page with "SimpleBlog by Raymond Camden"
no thing more.
Try debugging then. You should be able to see something if you do.
I'm implementing your code for a PhoneGap project the phonegap versión is 3.0, and I install inappbrowser plugin in order to open the web page in a native browser, but the link created for read more don't work with Window.open('Linkcreated').
I need some help please.
Did you use Window.open or window.open? It should be lower case. Do you see an error in the console?
Thanks for replay, this is the code:
$("#contentPage").live("pageshow", function(prepage) {
//Set the title
$("h1", this).text(entries[selectedEntry].title);
var contentHTML = "";
contentHTML += entries[selectedEntry].description;
contentHTML += '<img width="100%" src="' + entries[selectedEntry].imagen + '">';
contentHTML += '<a href="#" class="ui-btn ui-icon-eye ui-btn-icon-right ui-shadow ui-corner-all" onclick="window.open("' + entries[selectedEntry].url + '","_system")">read more.</a>';
$('#entryText',this).html(contentHTML);
});
sorry...
no i dont see any errors in console
When you use an onclick like that, you have to also return false. You would add that after the ).
I've ported this code in backbone/require applications, for more information see https://github.com/gabrycao...
Thanks for sharing that Gabriele.
You don't want to use Google for a JSONP server because Google caches the requests for as long as a week. Create your own JSONP RSS Feeds Server. See this article on CodeProject with full source code for creating RSS JSONP Feeds for PhoneGap Cordova Mobile Apps which explains JSONP in detail: http://www.codeproject.com/...
Well, that's only useful if you have access to the server itself. If you are parsing someone else's RSS feed, you can't just get a JSON/P version of it automatically.
And I think it would be *much* easier to simply append a dynamic value, as described here:
http://kmees.github.io/blog...
I've seen a few people recommend this for helping with Google caching.
Thank you very much for the good work Raymond, it works good when i test it on Android Virtual device but not on a real device. Could you tell me what could be the issue ?
No, but you could tell me. :) Use Remote Debugging to test and tell me what you see.
Ok Raymond i figured it out, the problem was the actual device was not working properly, i tested in two others it works perfect. Thanks man!!
Please tell me how to make rss feed mobile app for cross platform by using intel XDK
Sorry - I don't use that.
ok sir....
Hello thanks very much but i am currently developing a news app and needed to know how to get the news updates from within my area and breaking news update. i am developing the app using html, css, bootstrap, js, and J Query thanks
I'm sorry but I do not understand what you are asking. Can you rephrase it?
I asked how to use a code to get news updates around or within your town/community because I'm developing a news app but do not know how to get the code for any update
If I read you right, you are looking for a way to get news near where you live. I don't know what services exist for that. All I can recommend is what I'd do - Googling for it.