on Expert Tutorials

jQuery Mobile Advanced Tutorial – RSS reader app

11 comments
jquery-mobile
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon

Today’s tutorial is going to show you how you can use jQuery Mobile with PHP, MySQL and a bit of AJAX to build a small mobile web application.

At the end of this tutorial you will know how to add new RSS feed name and url into the database, how to delete the record from the database, how to fetch and parse a RSS feed and show its results inside jQuery Mobile list view.

If you are not familiar with jQuery Mobile, I suggest you read my jQuery Mobile basic tutorial and then come back.

So, let’s start. Many things in our RSS reader application will take place inside our index.php file. The front page of the application will have links for creating new RSS feed and Read existing feeds.

First of all we need a database table to store our feeds in. Create one using this SQL code:

CREATE TABLE IF NOT EXISTS `demo` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `url` varchar(256) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM

Now, I will create a db.php which will have a database connection and some basic functions for database handling. Create folder named inc and put your db.php file in it with this code pasted:

/*** mysql hostname ***/
$hostname = 'localhost';

/*** mysql username ***/
$username = 'root';

/*** mysql password ***/
$password = '';

$dbname = 'demo';

try 
{
    mysql_connect($hostname, $username, $password);
    mysql_select_db($dbname);
} 
catch (Exception $e) 
{
    // normally we would log this error
    echo $e->getMessage();    
}   

function db_select_list($query)
{
    $q = mysql_query($query);
    if (!$q) return null;
    $ret = array();
    while ($row = mysql_fetch_array($q, MYSQL_ASSOC)) {
        array_push($ret, $row);
    }
    mysql_free_result($q);
    return $ret;
} 

function db_select_single($query)
{
    $q = mysql_query($query);
    if (!$q) return null;
    $res = mysql_fetch_array($q, MYSQL_ASSOC);
    mysql_free_result($q);
    return $res;
}

This is a pretty basic code for connecting and fetching records from our database.

To keep things organized, I will put my header section inside external PHP file. Inside inc folder create file named header.php, then paste this in the header file:

<!DOCTYPE html>
<html>
   <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

   <title> Codeforest jQuery Mobile Tutorial </title> 

   <link rel="stylesheet"  href="http://code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.css" />
    
   <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
   <script type="text/javascript" src="http://code.jquery.com/mobile/1.0b2/jquery.mobile-1.0b2.min.js"></script>

   <link rel="apple-touch-icon" href="" />
</head>

This is basic HTML 5 header with included jQuery and jQuery Mobile.

Now create a file in your root directory and name it index.php and paste this in it:

<?php include('inc/header.php'); ?>
<body>
<div data-role="page" id="indexPage">
    <div data-role="header">
        <h1>Welcome!</h1>
    </div>
    <div data-role="content">
        <ul data-role="listview" data-inset="true">
            <li>
                <a href="#addNewFeedPage">Create New Feed</a>
            </li>
            <li>
                <a href="#listFeeds">Read RSS Feeds</a>
            </li>
        </ul>
    </div>
 
    <div data-role="footer">
        <h1> CodeForest </h1>
    </div>
</div>
</body>
</html>

Save everything and try it in your browser. Pretty cool.

As you can see our links to other pages look like anchor links. I am going to have multiple pages inside my index.php file and that is the way to link to them.

Now paste this whole code inside index.php overwriting the previous code:

<?php include('inc/header.php'); ?>
<body>
<div data-role="page" id="indexPage">
    <div data-role="header">
        <h1>Welcome!</h1>
    </div>
    <div data-role="content">
        <ul data-role="listview" data-inset="true">
            <li>
                <a href="#addNewFeedPage">Create New Feed</a>
            </li>
            <li>
                <a href="#listFeeds">Read RSS Feeds</a>
            </li>
        </ul>
    </div>
 
    <div data-role="footer">
        <h1> CodeForest </h1>
    </div>
</div>

<!-- addNewFeedPage -->
<div data-role="page" id="addNewFeedPage">
    <div data-role="header">
        <h1>Add New RSS Feed</h1>
        <a href="#indexPage" class="ui-btn-left"> Back </a>
    </div>

    <div data-role="content">
        <div data-role="content">
            <form id="newFeedForm" method="post">
                <div data-role="fieldcontain">
                    <label for="feedName"><strong>Feed Name:</strong></label>
                    <input type="text" name="feedName" id="feedName" value=""  />

                    <label for="feedUrl"><strong>Feed URL:</strong></label>
                    <input type="text" name="feedUrl" id="feedUrl" value="" />

                    <fieldset class="ui-grid-a">
                        <div class="ui-block-a"><a href="#indexPage" id="cancel" data-role="button">Cancel</a></div>
                        <div class="ui-block-b"><button data-theme="b" id="submit" type="submit">Submit</button></div>
                    </fieldset>
                    <h3 id="message"></h3>
                </div>
            </form>
        </div>
    </div>

    <div data-role="footer">
        <h1>Codeforest</h1>
    </div>
</div>

<!-- readFeedPage -->
<div data-role="page" id="listFeeds">
    <div data-role="header">
        <h1>RSS Feeds</h1>
        <a href="#indexPage" class="ui-btn-left"> Back </a>
    </div>
    <div data-role="content">

        <ul data-role="listview" data-theme="d" data-inset="true">
            <?php
                try
                {
                    include ("inc/db.php");
                    $result = mysql_query("SELECT * FROM demo");

                    while($row = mysql_fetch_array($result))
                    {
                        echo "<li><a rel=\"external\" href=\"./feed.php?id=" . $row['id'] . "\">" . $row['name'] . "</a></li>";
                    }
                }
                catch(Exception $e)
                {
                    echo $e->getMessage();
                }
            ?>
        </ul>
    </div>

    <div data-role="footer">
        <h1> CodeForest </h1>
    </div>
</div>
</body>
</html>

Above code is pretty simple. There are 3 pages, the indexPage, addFeedPage and readFeedPage. As we firstly have to add some feeds to read, let me show you how to do it.

As you can see, the AddNewFeedPage is basically a form for collecting New feed data (Feed name and Feed URL). Open your index.php in browser and click on Create New Feed link. You should see the form.

Now, add this JavaScript code directly before the closing body tag in your index.php file:

<script type="text/javascript">
    function resetTextFields()
    {
        $("#feedName").val("");
        $("#feedUrl").val("");
    }

    function onSuccess(data, status)
    {
        resetTextFields();
        // Notify the user the new post was saved
        $("#message").fadeIn(2000);
        data = $.trim(data);
        if(data == "OK")
        {
            $("#message").css("background-color", "#ffff00");
            $("#message").text("Feed is saved");
        }
        else
        {
            $("#message").css("background-color", "#ff0000");
            $("#message").text(data);
        }
        $("#message").fadeOut(5000);
    }

$(document).ready(function() {
    $("#submit").click(function(e){
 
        var formData = $("#newFeedForm").serialize();
 
        $.ajax({
            type: "POST",
            url: "addFeed.php",
            cache: false,
            data: formData,
            success: onSuccess
        });
 
        e.preventDefault();
    });
    
    
});
</script>

Above code is catching Submit button click event and making an AJAX call to addFeed.php file which will handle the database writing. Create an addFeed.php file and paste this in:

<?php
include('inc/db.php');

try
{
    $feedName       = mysql_real_escape_string($_POST['feedName']);
    $feedUrl        = mysql_real_escape_string($_POST['feedUrl']);

    if(!empty($feedName) && !empty($feedUrl)) {
    	mysql_query("INSERT INTO jquerydemo (name, url) VALUES ('$feedName', '$feedUrl')");
    	echo "OK";
    } else {
	echo "All fields are mandatory!";
    }
}
catch(Exception $e)
{
    // normally we would log this error
    echo $e->getMessage();
}

We are including our database file, sanitizing user input (you should never trust user entered data and always sanitize it!) and finally writing our entry in database. Now, go and add your RSS feed and save it. Make sure the feed URL is correct.

Now go back to your home page and click on Read RSS feeds link. You should see a feed name you just entered. Let me show you how to fetch and parse this feed.

Create a file named feed.php in your root directory and paste this in:

<?php
//include db file
include('inc/db.php');

//sanitizing user input
$feed_id = mysql_real_escape_string($_GET['id']);

$sql = "select * from demo where id = " . $feed_id;

$feed = db_select_single($sql);

$feedName = strtolower($feed['name']);

//cache file path and name
$cache = dirname(__FILE__) . "/cache/$feedName";

// we are caching for one hour
if(filemtime($cache) < (time() - 3600))
{
   if ( !file_exists(dirname(__FILE__) . '/cache') ) {
        mkdir(dirname(__FILE__) . '/cache', 0777);
   }
   // fetch the feed
   $url = $feed['url'];
   
   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $url);
   curl_setopt($ch, CURLOPT_HEADER, 0);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($ch, CURLOPT_FAILONERROR, 1);
   
   $f = curl_exec($ch);
   curl_close($ch);

   // If something was returned, we cache the whole XML file
   if ( !empty($feed)) {
       $cachefile = fopen($cache, 'wb');
       fwrite($cachefile, $f);
       fclose($cachefile);
   }
}
else
{
   // Use file from the cache
   $f = file_get_contents($cache);
}

include('feedData.php');

The comments in the code should help you to follow. What is going on here? First we include our db file, then sanitize user input and fetch the record form the database based on the id GET parameter from the link.

Then, we are checking if the cache file for that feed exists and if it is not older then 1 hour. If it exists, we are reading the feed from it. If not, we are getting the feed using URL fetched from the database and writing the response into cache file.

At the end, we are including the actual view file. Create feedData.php in your root folder and paste this in:

<?php include('inc/header.php'); ?>
<body> 

<div data-role="page">

   <header data-role="header" class="<?php echo $feedName . " feed"; ?>">
      <h1><?php echo ucwords($feedName); ?></h1>
      <a rel="external" href="./#listFeeds" class="ui-btn-left"> Back </a>
      <a rel="external" href="deleteFeed.php?id=<?php echo $feed_id; ?>" data-icon="delete" class="ui-btn-right"> Delete </a>
   </header><!-- /header -->

   <div data-role="content">    
      <ul data-role="listview" data-theme="d" data-inset="true">
      <?php
            $xml = new SimpleXMLElement($f);
            if(empty($xml->channel)) {
                echo '<li>Wrong feed format!</li>';
            } else {
            foreach($xml->channel->item as $post) {
            ?>

                <li>
                      <a style="white-space: normal;" target="_blank" rel="external" href="<?php echo $post->link;?>">
                     <?php echo $post->title; ?>
                     </a>
               </li>

      <?php } } ?>
      </ul>
   </div><!-- /content -->
   <footer data-role="footer">
      <h4> CodeForest </h4>
   </footer>
</div><!-- /page -->
</body>
</html>

This code is rendering the view. First we check if feed is valid and if it is parsing it using SimpleXMLElement. Go ahead and try it. If everything worked, you should see 10 titles from the feed which are links to the actual articles.

If something is wrong with the feed format and it is not in RSS feed format, you will get a nice message.

Notice the Delete button on top right. It is used so you can delete the feed you are viewing from the database. Create deleteFeed.php and paste the code for deleting in:

<?php
    include('inc/db.php');

    $feed_id = mysql_real_escape_string($_GET['id']);
    
    $sql = "delete from demo where id = " . $feed_id;
    
    mysql_query($sql);
    
    header ("Location: ./");

This code is including our db file, sanitizing user input from GET variable, deleting the feed from database and redirecting to home page.


I hope that this tutorial showed how easy it is to build mobile web applications using jQuery Mobile, PHP and MySQL.

Do you like jQuery Mobile? Are you using it or plan to use it? Do not hesitate to discuss in our comment section below. And if you have any questions, I will gladly answer them.

Stay tuned.

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon



  • This seems very cool. How difficult would it be to modify it so that you could present fixed RSS feeds to visitors … that is, with hard-coded RSS feed URLs so the visitor would not have the option of editing the list?

    • Hi Greg,

      you could take only the RSS parsing part and not read the feed form the database, but hardcode the address.

  • Thanks. I’m still working through the code to see what you’ve done, but once I understand everything I know about it, I’ll give that a try.

  • Nice work. It’s really hard to believe that only 5 years ago using your phone to surf the internet was only a thought. Now it’s a reality. The internet sure has come a long way. I always wounder what’s next.

  • Hi,
    Once a new feed is added, I would like to automatically go back to “#indexPage”. How can this be done. The “Feed is saved” message should be shown long enough before going back to “#indexPage”.
    Thanks

    • Hi Gaetan,

      you could add a redirect to #indexPage after $(“#message”).fadeOut(5000);

  • PIXART

    I would like to know how can i do to add special icon to each feed title.
    Thank you.

  • Super pumped for more of these. Definitely looking forward to the jQuery Mobile family. Things will be so much easier to build mobile sites in an all in one package.

  • Pingback: 55 Best Jquery TutorialDesign Freebies()

  • This was a fantastic tutorial thanks for including a demo example as well. jQM is very powerful and although it hasn’t caught up with Sencha Touch, it still provides the best mobile experience for the largest number of supported devices.

  • Thanks a lot for this tutorial