Tuesday, 14 December 2010

River of News, consuming a JSONP data feed

UPDATE:

With the release of JQUERY 1.5 this post is now out of date, also Dave is updating his JSONP feed to make consuming of the feed easier. Once this is completed I'll update the blog with a new post on, but for now see post on River of News news group .

Recently Dave Winer, a pioneer of RSS, published a river of news feed via JSONP. This article shows how to consume such a feed and the pitfalls of JSONP. For starters check out the demo at http://martimedia.com/news.htm

river-of-news

To create the page I made use of the following JavaScript libraries

  • jQuery – Makes writing clean / cross browser JavaScript a breeze
  • jQuery.templates –Separates the presentation (HTML) from code(js)
  • jQuery.jsonp – Provides jsonp error handling

Step 1 – Download the news feed

In the past I’ve just used the jQuery $.get command to download the feed, but luckly, Dave was having teething problems causing timeouts and formatting errors. But $.get wasn’t returning any feedback on these errors. After a bit of goggling I found the following article on StackOverflow which indicates that JSONP requests don’t make use of XHR hence lack of error handling. To overcome this problem jQuery.jsonp is recommended. This is similar to $.get but supports error handling for timeouts and invalid JSONP.

   1: $.jsonp({
   2:               dataType: 'jsonp',
   3:               timeout: 10000,
   4:               url: 'http://jsonp.scripting.com/daveRiver.json?callback=?',
   5:               success: function (data,status) {
   6:                     ProcessData(data);
   7:               },
   8:  
   9:               error: function(XHR, textStatus, errorThrown){
  10:                       if ( textStatus == "timeout")
  11:                           $("#newsFeed").text("Sorry, your request to scripting.com has timed out, please try again later");
  12:                       else if ( textStatus == "error")
  13:                           $("#newsFeed").text("Sorry, response from scripting.com is corrupted, please try again later");
  14:                   }
  15:       });

Step 2 – Process the news feed

Typically we would now write a load of jQuery to create HTML response, but in the new world of jQuery.templates we’re going to separate presentation from the code. This makes the code a lot cleaner and easier for others to reuse. In our example we’re not going to do any processing of the data, but just bind the data to the jQuery template with the following code:

   1: $("#newsFeed").html("");
   2: $("#newsTmpl").tmpl(data.updatedFeeds).appendTo("#newsFeed");

Step 3 – Generate HTML via a template

If you’re not familiar with templates then check out encosia blog . For Dave’s feed we have an array of feeds, which contain one or more stories. To keep us on our toes, Dave returns an object if the feed contains 1 item or an array for 2 or more items.

   1: <script id="newsTmpl" type="text/x-jquery-tmpl">
   1:  
   2:  
   3:   {{each(f,feed) updatedFeed}}
   4:       <h2>${feed.feedTitle}</h2>
   5:       {{if feed.item.length > 1 }}
   6:       {{each(i,item) feed.item}}
   7:  
   8:                   <div class='item'>
   9:                   <span class='date'>${format_date(item.pubDate)}</span> ${item.title} 
  10:                   <a href='${item.link}'>${get_hostname_from_url(item.link)}</a><br/><br/>
  11:                   </div>
  12:           
  13:           {{/each}}
  14:       {{else}}
  15:                   <div class='item'>
  16:                   <span class='date'>${format_date(feed.item.pubDate)}</span> ${feed.item.title} 
  17:                   <a href='${feed.item.link}'>${get_hostname_from_url(feed.item.link)}</a><br/><br/>
  18:                   </div>
  19:       {{/if}}
  20:  
  21:   {{/each}}
  22:   
</script>

Step 4 – Some formatting

To make it look pretty I made use of the colorzilla gradient editor , and a couple of helper functions to format the date and hostname.

Putting it all together in less than 100 lines of CSS/HTML/JS we have …..

   1: <!DOCTYPE html>
   2: <html >
   3:  
   4: <head>
   5:     <title>River of News</title>
   6:     <meta name="Description" content="Example of consuming a JSONP data feed (http://scripting.com) via jQuery and jQuery Templates." /> 
   7:  
   8:     <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.2.0/build/cssfonts/fonts-min.css">
   9:  
  10:     <style type="text/css">
  11:     body { /* generated via http://www.colorzilla.com/gradient-editor/ */
  12:     background: #87e0fd; /* old browsers */
  13:     background: -moz-linear-gradient(left, #87e0fd 0%, #53cbf1 40%, #05abe0 100%); /* firefox */
  14:     background: -webkit-gradient(linear, left top, right top, color-stop(0%,#87e0fd), color-stop(40%,#53cbf1), color-stop(100%,#05abe0)); /* webkit */
  15:     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#87e0fd', endColorstr='#05abe0',GradientType=1 ); /* ie */
  16:     }
  17:  
  18:     #page { width:800px; padding:20px 60px 20px 60px; margin:60px; min-height:600px; background:white; }
  19:     .date { font-size:80%; color:#888; vertical-align:top; }
  20:     #footer { padding-top:20px; }
  21:     </style>
  22: </head>
  23:  
  24: <body>
  25:  
  26: <div id="page" >
  27:  
  28:    <h1>River of News</h1>
  29:    <p>Powered by Dave Winer <a href="http://scripting.com/stories/2010/12/06/innovationRiverOfNewsInJso.html">river of news</a> feed</p>
  30:    <hr />
  31:                 
  32:        <div id='newsFeed'>Loading news from scripting.com, please wait.....
  33:        <!-- news feed via template inserted here -->
  34:        </div>
  35:  
  36:     <script id="newsTmpl" type="text/x-jquery-tmpl">
   1:  
   2:  
   3:     {{each(f,feed) updatedFeed}}
   4:         <h2>${feed.feedTitle}</h2>
   5:         {{if feed.item.length > 1 }}
   6:         {{each(i,item) feed.item}}
   7:                     <div class='item'>
   8:                     <span class='date'>${format_date(item.pubDate)}</span> ${item.title} 
   9:                     <a href='${item.link}'>${get_hostname_from_url(item.link)}</a><br/><br/>
  10:                     </div>
  11:             
  12:             {{/each}}
  13:         {{else}}
  14:                     <div class='item'>
  15:                     <span class='date'>${format_date(feed.item.pubDate)}</span> ${feed.item.title} 
  16:                     <a href='${feed.item.link}'>${get_hostname_from_url(feed.item.link)}</a><br/><br/>
  17:                     </div>
  18:         {{/if}}
  19:  
  20:     {{/each}}
  21:     
</script>
   1:  
   2:     <hr />
   3:     <p id=footer>Check out my <a href="http://martimedia.blogspot.com/">martimedia blog</a>, 
   4:     or my company website at <a href=http://martimedia.com/>martimedia.com</a></p>
   5: </div>
   6:  
   7: </body>
   8:  
   9: <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js">
   1: </script> 
   2: <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js">
   1: </script>
   2: <script type="text/javascript" src="http://jquery-jsonp.googlecode.com/files/jquery.jsonp-1.0.4.min.js">
   1: </script>
   2:  
   3: <script type="text/javascript">
   4:  
   5:     $(function () { 
   6:         $.jsonp({
   7:                 dataType: 'jsonp',
   8:                 timeout: 10000,
   9:                 url: 'http://jsonp.scripting.com/daveRiver.json?callback=?',
  10:                 success: function (data,status) {
  11:                         $("#newsFeed").html("");
  12:                         $("#newsTmpl").tmpl(data.updatedFeeds).appendTo("#newsFeed");
  13:                 },
  14:                 error: function(XHR, textStatus, errorThrown){
  15:                         if ( textStatus == "timeout")
  16:                             $("#newsFeed").text("Sorry, your request to scripting.com has timed out, please try again later");
  17:                         else if ( textStatus == "error")
  18:                             $("#newsFeed").text("Sorry, response from scripting.com is corrupted, please try again later");
  19:                         else
  20:                             $("#newsFeed").text("Error, status: " + textStatus + ", please try again later" );
  21:                     },
  22:         });
  23:  
  24:     });
  25:     
  26:     function format_date(date) {
  27:        var newDate = new Date( Date.parse(date));
  28:        return newDate.toLocaleTimeString();
  29:     }
  30:  
  31:     function get_hostname_from_url(url) {
  32:         url = url.match(/:\/\/(.[^/]+)/)[1];
  33:         url = url.replace("www.","").replace("feedproxy.","").replace("feeds.","");
  34:         return url;
  35:     }
  36:     
</script>
  37:   
  38: </html>

Feel free to use the code to create your own river of news, I just ask you to post your examples in the comments section below.

41 comments:

Ken said...

Thanks for the work and sharing the script. I've put it to use here: http://www.kenbooth.net/newsriver/

Julien said...

Nice! Can't wait to see people use http://superfeedr.com and its abritrary content support to subscribe to that JSON!

Shawn McCollum said...

Here's my entry based on your code.

http://tubejumper.com/winer_feed.html

havagan said...

Good excuse for me to finally play with jQuery. I went with a more "subtraction.com" inspired black & white theme.

http://river.havagan.com/

You can follow the design progression of the jQuery templates:

http://river.havagan.com/?template=feed_template_bw_detailed

http://river.havagan.com/?template=feed_template_bw_minimal_v1

http://river.havagan.com/?template=feed_template_bw_minimal_v2

(the current default template)

FooBarBoy said...
This comment has been removed by the author.
FooBarBoy said...

I never understood the idea of 'subscribing' to a json 'feed', but I'm starting to get the idea! Love these different templates!

Would love to learn how to make http://noagedanewsnetwork/ look cooler.

Thanks for starting the thread here MD!

AC

80dbf940-436a-11e2-824d-000bcdcb471e said...
This comment has been removed by a blog administrator.
80dbf940-436a-11e2-824d-000bcdcb471e said...
This comment has been removed by a blog administrator.
Kuang Chen said...
This comment has been removed by a blog administrator.
icemaker china said...
This comment has been removed by a blog administrator.
李彬彬 said...

This is such a great post, and was thinking much the same myself. Another great update.

Beas by dre

monclersolder said...

according to your post, i learn so many and thanks a lot!
Beats by Dre Solo

summerlijia said...

There are always bad days in one's life. So we should learn how to survive from hardship which could lead fatal consequences if the negative attitude was't handled properly. Listening to music and watching TV are good habits to unleash pressure. But as for me, I tend to choose to play WoW and I know a reliable store to buy WoW gold, if you happen to be a wow gamer too, I believe you will intersted in it. You will get 5% off by using the code "sssss" in that store. Catch the chance to get some cheap WoW gold

binbin Li said...

interesting site! I'm really like it! Very, very good!

beats by dre cheap

monclersolder said...

To begin with, The North Face Jackets when buying cheap apparel, it is very important Men's North Face Apex Bionic Jacket that you're walking clothing that suit you actually Women's North Face Denali Jacket very well .

Kuang Chen said...

Hi my family member! I wish to say that this post is amazing, great written and include almost all important infos. I would like to see extra posts like this .homemade chinese food recipes

Doug Williams said...

There is some really good features in this new version. The news feed is one of the jQuery features that I've actually been looking forwards to. Boise injury attorney

Doug Williams said...
This comment has been removed by the author.
Davis shang said...

After see your blog, I am agree with your thoughts, and hope you can share more of the information to us, wholesale led lightsand i will see your blog update often . or you may like us to . waterproof led light strips,
RGB LED strips,i hope you like it !

370seo said...

Another excellent example of innovation, I am happy to locate it. There are so many developers working on this segment but this is one of the best innovative idea ever. Thanks for sharing it here replica watches

370seo said...

There is some really good features in this new version. The news feed is one of the jQuery features that I've actually been looking forwards to.basket jordan pas cher|airmax|jordan femme pas cher|basket jordan pas cher

9b03441e-a7d2-11e2-ace2-000bcdcb471e said...

This site seems to receive a great deal of visitors. How do you promote it? It gives a nice individual twist on things. I guess having something authentic or substantial to give info on is the most important factor.Adidas Zapatos Fútbol

9b03441e-a7d2-11e2-ace2-000bcdcb471e said...

great! this site is so far I feel best, this site has a lot of interesting content, it is worth a visit Mænd Nike Free Run

chu huong said...

I find your blog cool. Please continue making things like this...


WOW gold

7ed62176-acaf-11e2-8dcd-000bcdcb5194 said...

meme sans les avantages physiques evidentes, une dose quotidienne de rire chaleureux est sain pour tout le monde.tn pas cher

7ed62176-acaf-11e2-8dcd-000bcdcb5194 said...

puis je suis passe a ecrire des livres et un motif ecriture quotidienne.tn requin pas cher

Momo Wu said...

Your site is good Actually, i have seen your post and That was very informative and very entertaining for me. Thanks for posting Really Such Things. I should recommend your site to my friends. Cheers.Beijing city discovery

Momo Wu said...

certainly a fantastic piece of work ... It has relevant information. Thanks for posting this.guide guilin chine

Momo Wu said...

Your blog is so interesting and very informative.Thanks sharing. Definitely a great piece of work Thanks for your work.mac photo recovery

Lisa Helen said...

Keep Looking for something more that uplift my mind capability. Keep it up.

layer cake style leather jacket

佘丽丽 said...
This comment has been removed by the author.
Chris Grant said...

Thank you for sharing the script :) the tankless water heater

83bc37e8-b38f-11e2-a9f0-000bcdcb471e said...

I like the valuable information you provide in your articles. I’ll bookmark your weblog and check again here often. Best of luck for the next! Baby Bedding Info

Chris Grant said...

Very informative and helpful. I was searching for this information but there are very limited resources. Thank you for posting. affordable snap on mechanics tool set

a0cb7efa-0dff-11e3-a79e-000bcdca4d7a said...

You made a few fine points there. I did a search on the subject and found nearly all folks will consent with your blog.Corporate Gifts

a0cb7efa-0dff-11e3-a79e-000bcdca4d7a said...

I'm satisfied to seek out so many helpful information here in the submit, we need develop extra techniques in this regard, thank you for sharing. .http://www.wholesale-vietnam.com

jimmy wilson said...

Great write up it sounds good
Superman Life Jacket

Frandis Charles said...

Fantastic!

Harley Davidson Marlboro Man Jacket Sale

a0cb7efa-0dff-11e3-a79e-000bcdca4d7a said...

I know my handwriting changes depending on what I am writing. I also think the fact that pretty much nothing is written by hand today; from a college to an email, that this can affect people's handwriting for the worse Kate Spade Sale

3af61e96-28b7-11e3-855a-000bcdcb5194 said...

This is highly informatics, crisp and clear. I think that Everything has been described in systematic manner so that reader could get maximum information and learn many things 4vindictus.com

df857824-5a46-11e3-8140-000bcdcb2996 said...

All the contents you mentioned in post is too good and can be very useful. I will keep it in mind, thanks for sharing the information keep updating, looking forward for more posts.E40 led corn lamps 80w