- Part 1: Google, Twitter, and AngularJS
- Part 2: Let's Make a Feed Reader
- Part 3: Rendering Feeds
- Part 4: Managing Feeds
Previously
In the last part we looked at fetching and parsing feeds with YQL using Angular’s $http
service. The commit for that part was 2eae54e
.
This week you’ll learn more about Angular’s data binding by adding some i
...
- Part 1: Google, Twitter, and AngularJS
- Part 2: Let's Make a Feed Reader
- Part 3: Rendering Feeds
- Part 4: Managing Feeds
Previously
In the last part we looked at fetching and parsing feeds with YQL using Angular’s $http
service. The commit for that part was 2eae54e
.
This week you’ll learn more about Angular’s data binding by adding some input
fields to allow feeds to be added and removed.
If you get stuck at any part of this tutorial, check out the full source here: commit c9f9d06.
Modeling Multiple Feeds
The previous part mapped one feed to a view by using the $scope.feed
object. Now we want to support multiple feeds, so we’ll need a way of modeling ordered collections of feeds.
The easiest way to do this is simply by using an array. Feed objects that contain the post items and feed URLs can be pushed onto the array:
$scope.feeds=[{url:'https://dailyjs.com/atom.xml',items:[/* Blog posts go here */]}];
Rendering Multiple Feeds
The view now needs to be changed to use multiple feeds instead of a single feed. This can be achieved by using the ng-repeat
directive to iterate over each one (app/views/main.html
):
<divng-repeat="feed in feeds"><ul><ling-repeat="item in feed.items"><ahref=""></a></li></ul>
URL: <inputsize="80"ng-model="feed.url"><buttonng-click="fetchFeed(feed)">Update</button><buttonng-click="deleteFeed(feed)">Delete</button><hr/></div>
The fetchFeed
and deleteFeed
methods should be added to $scope
in the controller, but we’ll deal with those later. First let’s add a form to create new feeds.
Adding Feeds
The view for adding feeds needs to use an ng-model
directive to bind a value so the controller can access the URL of the new feed:
<div>
URL: <inputsize="80"ng-model="newFeed.url"><buttonng-click="addFeed(newFeed)">Add Feed</button></div>
The addFeed
method will be triggered when the button is clicked. All we need to do is push newFeed
onto $scope.feed
then clear newFeed
so the form will be reverted to its previous state. The addFeed
method is also added to $scope
in the controller (app/scripts/controllers/main.js
), like this:
$scope.addFeed=function(feed){$scope.feeds.push(feed);$scope.fetchFeed(feed);$scope.newFeed={};};
This example could be written to use $scope.newFeed
instead of the feed
argument, but don’t you think it’s cool that arguments can be passed from the view just by adding it to the directive?
Fetching Feeds
The original $http
code should be wrapped up as a method so it can be called by the ng-click
directive on the button:
$scope.fetchFeed=function(feed){feed.items=[];varapiUrl="https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%3D'";apiUrl+=encodeURIComponent(feed.url);apiUrl+="'%20and%20itemPath%3D'feed.entry'&format=json&diagnostics=true&callback=JSON_CALLBACK";$http.jsonp(apiUrl).success(function(data,status,headers,config){if(data.query.results){feed.items=data.query.results.entry;}}).error(function(data,status,headers,config){console.error('Error fetching feed:',data);});};
The feed
argument will be the same as the one in the $scope.feeds
array, so by clearing the current set of items using feed.items = [];
the user will see instant feedback when “Update” is clicked. That makes it easier to see what’s happening if the feed URL is changed to another URL.
I’ve used encodeURIComponent
to encode the feed’s URL so it can be safely inserted as a query parameter for Yahoo’s service.
Deleting Feeds
The controller also needs a method to delete feeds. Since we’re working with an array we can just splice
off the desired item:
$scope.deleteFeed=function(feed){$scope.feeds.splice($scope.feeds.indexOf(feed),1);};
Periodic Updates
Automatically refreshing feeds is an interesting case in AngularJS because it can be implemented using the $timeout
service. It’s just a wrapper around setTimeout
, but it also delegates exceptions to $exceptionHandler
.
To use it, add it to the list of arguments in the controller and set a sensible default value:
angular.module('djsreaderApp').controller('MainCtrl',function($scope,$http,$timeout){$scope.refreshInterval=60;
Now make fetchFeed
call itself, at the end of the method:
$timeout(function(){$scope.fetchFeed(feed);},$scope.refreshInterval*1000);
I’ve multiplied the value by 1000
so it converts seconds into milliseconds, which makes the view easier to understand:
<p>Refresh (seconds): <inputng-model="refreshInterval"></p>
Conclusion
Now you can add more feeds to the reader, it’s starting to feel more like a real web application. Over the next few weeks I’ll add tests and a better interface.
The code for this tutorial can be found in commit c9f9d06.
Read more https://feedproxy.google.com/~r/dailyjs/~3/v8yX0yzR-rs/angularjs-4