Last year I’ve written a few lines about aggregating feeds with SimplePlie. SimplePie is a nice PHP library but the version I used broke when my hosting provider decided to upgrade the servers to a new PHP version. Although a new version was quickly installed, I found the broken pages to be the perfect motivation to finally do some coding with AngularJS.So after having attended a few workshops about AngularJS, and having read the excellent book by Brad Green and Shyam Seshadri, I finally got around to do some actual work with the framework.
The basic idea was to develop a page where feeds from several sources are shown so you won’t have to visit each page individually to check out the latest news. You can check out examples of what I intended to do: RSS Reader.
I got ready to develop some JavaScript code to download RSS feeds but then I learned about the Google Feed API, saving me alot of time. With Google’s Feed API, you can download any public Atom, RSS, or Media RSS feed using only JavaScript, and in the format of yout chosing – in my case JSONP.
So what I ended up with is a very basic HTML page sprinkled with a few AngularJS directives:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!DOCTYPE html> <html ng-app='feedModule'> <head> <script type="text/javascript" src="https://www.google.com/jsapi"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular-resource.min.js"></script> </head> <body ng-controller='FeedCtrl'> <div ng-repeat="feed in feeds | orderBy:'title'"> <h2><a href="{{feed.link}}" target="_blank">{{feed.title}}</a></h2> <p><span ng-repeat="item in feed.entries"> <a href="{{item.link}}" target="_blank">{{item.title}}</a> (<span>{{item.publishedDate | date:'d-MM-yyyy HH:mm'}}</span>)<br /> </span></p> </div> <script src="feeds.js"></script> </body> </html> |
Nothing very interesting going on here. The interesting parts take place in the accompanying Angular script feed.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
var feeds = []; angular.module('feedModule', ['ngResource']) .factory('FeedLoader', function ($resource) { return $resource('http://ajax.googleapis.com/ajax/services/feed/load', {}, { fetch: { method: 'JSONP', params: {v: '1.0', callback: 'JSON_CALLBACK'} } }); }) .service('FeedList', function ($rootScope, FeedLoader) { this.get = function() { var feedSources = [ {title: 'Slashdot', url: 'http://rss.slashdot.org/Slashdot/slashdot'}, {title: 'Tweakers', url: 'http://feeds.feedburner.com/tweakers/mixed'}, {title: 'Wired', url: 'http://feeds.wired.com/wired/index'}, ]; if (feeds.length === 0) { for (var i=0; i<feedSources.length; i++) { FeedLoader.fetch({q: feedSources[i].url, num: 10}, {}, function (data) { var feed = data.responseData.feed; feeds.push(feed); }); } } return feeds; }; }) .controller('FeedCtrl', function ($scope, FeedList) { $scope.feeds = FeedList.get(); $scope.$on('FeedList', function (event, data) { $scope.feeds = data; }); }); |
The controller FeedCtrl places the feeds retrieved from the get() method of the FeedList service on the $scope. It also registers itself as as a listener on the FeedList in case the data has changed.
The FeedList service contains one method – get() – that holds an array of feed URLs. For each URL it calls FeedLoader.fetch() to retrieve the actual feeds. All the feeds are then placed in an array which is returned to the calling method.
FeedLoader is created with an AngularJS $resource factory. The result is an object that let’s us interact with REST services in a very simple manner. As you can see, it only takes a single line of code to interact with the Google Feed service.
Of course, this is a very simple example but enough to fulfil my requirements. Taking this example as a starting point, it is very easy to show extra information from the feed items e.g. the actual contents. You might also want to sort the feeds based on the date instead of based on the source.
is there any replacement for google feed api
this is help full,i got it….
Hi Wim ,
at line 18 -19 where is the data coming from
function (data) {
var feed = data.responseData.feed;
feeds.push(feed);}
trying to define the anoymous function outside the loop, but can figure where the data argument is defind
Have a look at the fetch() method at line 6.
See the official documentation on $resource for more information: https://docs.angularjs.org/api/ngResource/service/$resource
Hi thanks for ur quick reply , i fix the data problem , but i have another problem , i can get correct index
on feed[x].entries[x] on loading multiple feed source , am passing to detail view template using
/news/$parentindex/$index
Index is correct but the new items that appears is from a different feed source
Hello..
Thanks for tutorial. I’ve a small question.
I’ve a tab menu with 3 tabs.
First tab: Slashdot
Second tab: Tweakers
Third: Wired
How can list content each tab.
I tried somethings like this http://pastebin.com/xMtaYkJg But it doesnt work.
Thanks..
For information, here is another way to get a callback once all feeds have been loaded :
$scope.feedSources = [
{title: 'Raspberry Pi Home Server', lang: "fr", defaultImage: "", url: 'http://www.pihomeserver.fr/feed'},
];
$scope.feeds = [];
$scope.getFeed = function(feedSource, callback) {
return FeedLoader.fetch({q: feedSource.url, num: 10}, {}, function (data) {
return callback(data.responseData.feed);
});
}
$scope.getFeeds = function (callback) {
var promises = [];
$scope.feedSources.forEach(function (obj, i) {
promises.push($scope.getFeed(obj, function(value){
$scope.feeds.push(value);
}));
});
$q.all(promises).then(function () {
callback();
});
}
// $scope.getFeed(0, function(result){console.log(result)})
$scope.getFeeds(function(){
console.log('End')
})
Usefull in my case when i want to perform actions once i’m sure to get all feeds loaded
Hi ,could explain further – need to use the callback system , getting undefined for some values esp how to use this in the controller service model – your code does not specify controller or services
Nothing to say except thank you ! Work like a charm after a simple copy/paste !
You saved me time !
How can I replace $resource with $http in this code? I don’t want to load angular-resource.js
Hi Vaz, $resource is basically a thin wrapper around $http. So you should be able to replace one by the other very easily. The AngularJS team has provided excellent documentation, just have a look at their API: https://docs.angularjs.org/api/ng/service/$http#jsonp.
Regards,
Wim
Hi wim,
in your script of feed.js in line 16, i just wondering when the feeds variable is loaded it’s content? could you please explain it, i am a newbie in angular.js. Thanks before
Hi Faisal,
In line 16 I check to see if the array declared at line 1 already holds data. If so, there is no need to retrieve it again. If there is no data present, it is retrieved in lines 17-22, and added to the feeds array, by using the FeedLoader.fetch() method (see lines (4-8).
Hope this clarifies it somewhat.
Regards,
WIm
We just created a very similiar project with the Superfeedr API and it works really well! Thanks for the tip!