Posted in Mobile, jQuery, JavaScript, HTML5 | Posted on 10-11-2011 | 6,356 views
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:
2//Title of the blog
3var TITLE = "ColdFusion Jedi";
4//RSS url
5var 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.
2 var xml = $(res);
3 var items = xml.find("item");
4 $.each(items, function(i, v) {
5 entry = {
6 title:$(v).find("title").text(),
7 link:$(v).find("link").text(),
8 description:$.trim($(v).find("description").text())
9 };
10 entries.push(entry);
11 });
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:
2 <ul id="linksList" data-role="listview" data-inset="true"></ul>
3</div>
So my handler can simply append to it....
2var s = '';
3$.each(entries, function(i, v) {
4 s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>';
5});
6$("#linksList").append(s);
7$("#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:
2
3 <div data-role="header">
4 <a href="#mainPage" data-rel="back">Home</a>
5 <h1></h1>
6 </div>
7
8 <div data-role="content" id="entryText">
9 </div>
10
11</div>
And I've got a JavaScript click handler that notices the clicks and populates the data. First, the event listener for the link:
2$(".contentLink").live("click", function() {
3 selectedEntry = $(this).data("entryid");
4});
And then the page displayer...
2$("#contentPage").live("pageshow", function(prepage) {
3 //Set the title
4 $("h1", this).text(entries[selectedEntry].title);
5 var contentHTML = "";
6 contentHTML += entries[selectedEntry].description;
7 contentHTML += '<p/><a href="'+entries[selectedEntry].link + '">Read Entry on Site</a>';
8 $("#entryText",this).html(contentHTML);
9});
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:
2<html>
3 <head>
4 <meta name="viewport" content="width=device-width, initial-scale=1">
5 <title></title>
6 <link rel="stylesheet" href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" />
7 <script src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
8 <script src="main.js"></script>
9 <script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js"></script>
10</head>
11<body>
12
13<div data-role="page" id="mainPage">
14
15 <div data-role="header">
16 <h1></h1>
17 </div>
18
19 <div data-role="content">
20 <ul id="linksList" data-role="listview" data-inset="true"></ul>
21 </div>
22
23 <div data-role="footer">
24 <h4>SimpleBlog by Raymond Camden</h4>
25 </div>
26
27
28</div>
29
30<div data-role="page" id="contentPage">
31
32 <div data-role="header">
33 <a href="#mainPage" data-rel="back">Home</a>
34 <h1></h1>
35 </div>
36
37 <div data-role="content" id="entryText">
38 </div>
39
40</div>
41
42</body>
43</html>
And the main.js file:
2
3 //EDIT THESE LINES
4 //Title of the blog
5 var TITLE = "ColdFusion Jedi";
6 //RSS url
7 var RSS = "http://feedproxy.google.com/RaymondCamdensColdfusionBlog";
8 //Stores entries
9 var entries = [];
10 var selectedEntry = "";
11
12 //listen for detail links
13 $(".contentLink").live("click", function() {
14 selectedEntry = $(this).data("entryid");
15 });
16
17 //Listen for main page
18 $("#mainPage").live("pageinit", function() {
19
20 //Set the title
21 $("h1", this).text(TITLE);
22
23 $.get(RSS, {}, function(res, code) {
24 var xml = $(res);
25 var items = xml.find("item");
26 $.each(items, function(i, v) {
27 entry = {
28 title:$(v).find("title").text(),
29 link:$(v).find("link").text(),
30 description:$.trim($(v).find("description").text())
31 };
32 entries.push(entry);
33 });
34
35 //now draw the list
36 var s = '';
37 $.each(entries, function(i, v) {
38 s += '<li><a href="#contentPage" class="contentLink" data-entryid="'+i+'">' + v.title + '</a></li>';
39 });
40 $("#linksList").append(s);
41 $("#linksList").listview("refresh");
42 });
43
44 });
45
46 //Listen for the content page to load
47 $("#contentPage").live("pageshow", function(prepage) {
48 //Set the title
49 $("h1", this).text(entries[selectedEntry].title);
50 var contentHTML = "";
51 contentHTML += entries[selectedEntry].description;
52 contentHTML += '<p/><a href="'+entries[selectedEntry].link + '">Read Entry on Site</a>';
53 $("#entryText",this).html(contentHTML);
54 });
55
56});


Funny how when you read documentation you can miss things you aren't looking for...
Henry
For some reason adding these did not work for me
// show
$.mobile.pageLoading();
// hide
$.mobile.pageLoading(true);
Thank you
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("")
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>
$.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
Thanks
<!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);
});
});
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.
This is amazing! It works perfect on the iPhone too :)
I was wondering, would this support RSS images too?
My JS knowledge is pretty poor, but I'm learning :)
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
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.
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/Tsk7G/
Thanks a lot,
Mike
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 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! :)
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
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
And thank you for bringing this up. I was remis in not supporting that immediately. I apologize!
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.. :)
http://www.raymondcamden.com/index.cfm/2011/12/19/...
Thank you!
[Add Comment] [Subscribe to Comments]