Creating an Angular 2 RSS reader app

von Javier Puerto
Tags: Material Design , TypeScript , Angular , Open Source , Tutorial

AngularJS was one of the most famous JavaScript frameworks in the previous years. Angular 2 was released finally at 2016-09-15 after many changes to introduce one of the most promising frameworks to keep the leadership in the next years. I have been following the Angular 2 development and the final release is out. We are ready to use it, not only for playing!

The code has been updated to latest stable. See how to update your Angular application in the new post.

Angular 2 vs. AngularJS

Angular 2 is completely different from AngularJS! We are not going to talk about this deeply but let me explain an overview of the differences.

  • Angular 2 is based on TypeScript. Don't panic! TypeScript is JavaScript at the end but it is a big change because it makes our development more robust as our development is typed. The errors should appear now in build time and not runtime. This fact also introduces some great features:
  • Types
  • Generics
  • Lambdas
  • Annotations

  • Angular 2 is based on components while AngularJS was based on Controllers and Directives. This simplifies the develpment as we do not need to make a ceremony and create a lot of code just to integrate new business logic. Forget about the $scope variable, a component is a directive with template and business logic included.

  • Angular 2 dependency injection has been improved quite a lot, by just creating an @Injectable. The services have never been so easy to create, forget about the bunch of Factories, Services, Providers …

There are many more changes that make creating applications with this framework an enjoyable experience and definitely recommended.

Create an Angular 2 RSS reader

We are going to create a simple application based on Angular 2 framework. The application will consist of an RSS news reader for our BeCompany blog. For the design we are going to use the nice Material Design proposed by Google that also provides a beta integration for Angular 2.

What do we need?

Our application will be quite simple. The layout will consist of:

  • A toolbar with the application title and button to refresh the feed.
  • A list of MD cards for each feed entry that will display the following information:
  • Title
  • Author
  • Publication date
  • Summary of the post

Creating the base project

We are going to use the awesome tool angular-cli provided by the developers of Angular 2.

$ npm install -g angular-cli
$ ng new angular2-rss-reader-tutorial

These commands will take a while because they will take care of installing all the required dependencies but at the end we will have a working project to develop with the Angular 2 framework.

$ cd angular2-rss-reader-tutorial
$ ng serve

Visit the URL http://localhost:4200 to see the base app working. All the changes made will be reflected in the browser instantly.

Developing the components

Now it is time to get our hands dirty with the implementation of the components. With the help of the ng tool, the developing process becomes easier as we can reduce writing code to the minimum, just taking care of the implementation and leaving the dependency injection and scaffolding to the tool.

Creating a FeedService

The problem with an RSS reader is that RSS is not intended to be read by JavaScript. It is XML based, which is not a nice language to work for JS and it implies external calls that triggers security issues as makes cross site requests. To solve this problem, Google had their free service but unfortunately the service is going to be removed soon. Thanks to the guys from rss2json we can enjoy another free service that converts the RSS to JSON.

Creating the FeedService:

$ ng g service feed-service

The tool will directly create the needed files and import them in the main app module. Now we have to take care of the implementation, as we said at the beginning of the article, Angular 2 is based on TypeScript and we need to define the types of the feeds to work with it. A closer look at the rss2json API reveals the properties and types of data that the service exposes.

We will need a Feed type to store the main service result, then FeedInfo for the global information, and a FeedEntry that will contain the details of the different entries.

$ ng g interface model/feed
$ ng g interface model/feed-info
$ ng g interface model/feed-entry

The tool will automatically generate empty ts files that we can just populate with the proper attributes that the rss2json service provides. Notice that the file names are all lower case and use dashes, the tool automatically creates the type names as camel case. Then we can create the FeedService code.

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import {Observable} from 'rxjs/Rx';
import { Feed } from './model/feed';

@Injectable()
export class FeedService {

  private rssToJsonServiceBaseUrl: string = 'https://rss2json.com/api.json?rss_url=';

  constructor(
    private http: Http
  ) { }

  getFeedContent(url: string): Observable<Feed> {
    return this.http.get(this.rssToJsonServiceBaseUrl + url)
            .map(this.extractFeeds)
            .catch(this.handleError);
  }

  private extractFeeds(res: Response): Feed {
    let feed = res.json();
    return feed || { };
  }

  private handleError (error: any) {
    // In a real world app, we might use a remote logging infrastructure
    // We'd also dig deeper into the error to get a better message
    let errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';
    console.error(errMsg); // log to console instead
    return Observable.throw(errMsg);
  }
}

As you can see, the code is self explanatory. It is annotated with the @Injectable, making it a candidate to be injected by the Angular 2 DI system in the same way as the http service is being injected in this service's constructor. It contains a single public method getFeedContent(url) that will return an Observable object with the Feed. More information about the Observable pattern can be found in the rxjs github page and integration with Angular 2 can be found in the official documentation.

Creating FeedComponent

We have a service which we can reuse for any Angular 2 project that we want. Now we have to do something more visible to the user, we need to populate the page with this information. As we want to use the Material Design components, we need to install it first.

$ npm install -save @angular2-material/button \
                    @angular2-material/card \
                    @angular2-material/core \
                    @angular2-material/icon \
                    @angular2-material/toolbar

This will save the dependencies into the node_modules directory. We need to load them by importing the needed libraries into our main module. Then we can start creating the component.

$ ng g component feed-card

This command will create the needed files in a structure as follows:

src/app/feed-card/
├── feed-card.component.css
├── feed-card.component.html
├── feed-card.component.spec.ts
└── feed-card.component.ts

Notice that all the changes are included directly in the main app module by the angular-cli command so we do not have to take care of that, just define the components. The component structure is also quite simple and self explanatory:

  • The .ts file will contain the logic of the component.
  • The .scpec.ts file will contain the component spec for the unit tests.
  • The .html file will contain the component template.
  • The .css file will contain the component styles.

That makes very easy to create new components and reuse them for any other projects that we want. But let's have a look into the contents.

feed-card.component.ts

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-feed-card',
  templateUrl: './feed-card.component.html',
  styleUrls: ['./feed-card.component.css']
})
export class FeedCardComponent implements OnInit {

  @Input() feed: any;

  constructor() { }

  ngOnInit() {
  }

}

feed-card.component.html

<md-card class="card-feed-entry">
  <md-card-title>{{feed.title}}</md-card-title>
  <md-card-subtitle>{{feed.author}} - {{feed.pubDate | date:'dd-MM-yyyy'}}</md-card-subtitle>
  <md-card-content>{{feed.description}}</md-card-content>
</md-card>

That is so clear, the component logic define a custom element app-feed-card that is parametrizable by the annotated @Input feed parameter. This makes possible to call our new defined element as:

<app-feed-card [feed]="OUR_FEED_OBJECT"></app-feed-card>

In the template we use a pipe to format the date to something nicer for the user's presentation. A pipe works similar to Unix pipes, indeed it uses the pipe ("|") character and performs a post-processing of the variable passed as argument. Angular 2 contains some predefined pipes already but we can create our own to adjust to our needs.

Creating HTMLStrip pipe

The rss2json service does a good job but the contents and summary contains HTML tags that we want to remove. We will need to create a custom pipe to strip these unwanted HTML tags. As it is from our blog, the source will be safe but it is also a good practice to avoid XSS attacks.

$ ng g pipe pipe/strip-html-tags

As before, the angular-cli tool will take care of generating the needed files and even add it to the main app module for usage. We just have to take care of writing the implementation. For this we are not going to reinvent the wheel and we are going to take an implementation seen in Stackoverflow.

Put everyting together

We have all the required components and tools to create our app, we can now use them in the main application component. Let's take a look at the code logic:

app.component.ts

import { Component, OnInit } from '@angular/core';
import { FeedService } from './feed.service';

// Add the RxJS Observable operators we need in this app.
import './rxjs-operators';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  private feedUrl: string = 'https%3A%2F%2Fwww.becompany.ch%2Fen%2Fblog%2Ffeed.xml';
  private feeds: any;

  constructor (
    private feedService: FeedService
  ) {}

  ngOnInit() {
    this.refreshFeed();
  }

  private refreshFeed() {
    this.feedService.getFeedContent(this.feedUrl)
        .subscribe(
            feed => this.feeds = feed.items,
            error => console.log(error));
  }

}

app.component.html

<md-toolbar color="primary">
  <span class="right"><button md-button (click)="refreshFeed()"><md-icon >refresh</md-icon></button></span>
  <span class="center">BeCompany news</span>
</md-toolbar>

<app-feed-card *ngFor="let feed of feeds" [feed]="feed" ></app-feed-card>

First, we defined a private attribute with the BeCompany RSS URL encoded for usage as GET parameter. We also define a feeds attribute that will contain an array of feed entries. The component implements Angular OnInit interface so we have to implement the method ngOnInit(), as you can imagine, this method is called on component initialization and will leave us with an initialized state populating the feeds.

The template uses the Material Design toolbar to define a static title and a right-aligned button that has a click event bound to the method refreshFeed(). When the button is clicked, the method will be called and Angular 2 will take care of refreshing the view with the new computed values. We then made use of our custom component FeedCard by using and old AngularJS friend, an ng-for directive. If you have worked with the previous framework version, this will surprise you as the directives are now called with an "*" instead of the old ng-directive style. What this directive does is to iterate over a collection of elements repeating the enclosed tag with the parameters available. With this simple sentence, we can create as many cards as feed entries exist in the private variable feeds.

Build a deployable app

At this point, we are ready to build the application. If you do not want to get your hands dirty by coding it, you can directly download the application from the GitHub repository. Do not forget to explicitly install the npm dependencies by hand and test with the ng serve command. To release a production application we only need to run the build tool:

$ ng build --target=production --environment=prod

That's all. Please note that this tutorial is not a step-by-step guide and shows an overview of the whole process of developing an application based in the new Angular 2 framework. Some implementation details are left to the user but the full code is provided as reference in the BeComany GitHub repository. I hope that you have enjoyed the article, and good luck with Angular 2 developing!