Blog

- December 30, 2015

A few days ago the Angular team released the first beta version of Angular 2. They made a funny announcement in Developer News Worldwide for December 15 2015.

To celebrate this great news, we created a simple Angular 2 application that interacts with a Web API implemented and hosted within the APISpark platform.

During the post, we will describe the key features of Angular 2 and how to implement the link between this application and the remote Web API.

Designing the application

Angular 2 provides a completely different approach than version 1 of the framework. The component is at the heart of applications. Controllers and scopes have completely disappeared. Around this concept of component, we still find notions of dependency injection and routing that were available with the previous version.

The following figure describes all the parts of your application and the built-in objects that we will use.

angular2-app-architecture

Let’s start to implement our application.

Implementing foundations

You may already be aware that Angular 2 applications can be implemented using different languages like ES5 or ES6 / TypeScript. The problem with the latter is that such languages aren’t natively supported by browsers yet. To execute such applications built with those languages, a “transpilation” phase is required, to translate the language into earlier versions of JavaScript supported by the browsers.

Two approaches are possible here:

  • Static transpilation. In this case, the operation is done locally. This means that preprocessing is required to transform Typescript files into JavaScript ones. Only the latter are executed within the browser.
  • On the fly transpilation. In this case, everything is handled in the browser itself. A library is responsible for converting Typescript source files into JavaScript files executable in the browser.

We will use here the “on the fly” transpilation for more convenience. For this reason, we need to include JavaScript libraries for TypeScript and SystemJS in addition to the ones for Angular 2 itself. The following content corresponds to the index.html file that you will load in a browser to display the application.

<!DOCTYPE html>
<html>
  <head>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <title>Angular2 - APISpark</title>
    <script src="https://rawgithub.com/systemjs/systemjs/0.19.6/dist/system.js"></script>
    <script src="https://code.angularjs.org/tools/typescript.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/angular2-polyfills.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/Rx.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/angular2.dev.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/router.dev.js"></script>
    <script>
      System.config({
        transpiler: 'typescript',
        typescriptOptions: { emitDecoratorMetadata: true },
        packages: {'src': {defaultExtension: 'ts'}}
      });
      System.import('src/boot')
            .then(null, console.error.bind(console));
    </script>
  </head>
  <body>
    <apispark-app>Loading...</apispark-app>
  </body>
</html>

The boot.ts file that is imported in the index.html file corresponds to the entry point of our application. This allows us to import and bootstrap it using the bootstrap function. Since we will use Angular 2 routing and HTTP supports, we need to specify both ROUTER_PROVIDERS and HTTP_PROVIDERS as dependencies of our main component.

import {bootstrap} from 'angular2/platform/browser';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {HTTP_PROVIDERS} from 'angular2/http';

import {ApisparkApp} from './apispark-app';

bootstrap(ApisparkApp, [
  ROUTER_PROVIDERS, HTTP_PROVIDERS,
]);

We can now implement our application with confidence. Our first task will be to tackle routing.

Defining routes

Like with version 1, Angular 2 lets us define routing within our application. According to this support, components can be displayed according to paths. Within our application we will have the following routes:

  • Route with path : display the CompanyList component
  • Route with path : display the CompanyDetails component

The RouteConfig annotation of Angular on the ApisparkApp component accepts an array of objects with the following attributes:

  • path: the path used to display the component
  • component: the class of the component
  • name: the name used to display this route
  • useAsDefault: if the route is the default one

Within your application, you will have the following configuration:

@RouteConfig([
  { path: '/', component: CompanyList, name: 'Home', useAsDefault: true }
  { path: '/:id', component: CompanyDetails, name: 'Details' }
])
export class ApisparkApp {
}

By default, routing uses the HTML5 history. This means that URLs will be exactly what was specified. If you want to use the hashbang approach instantiated, you can specify the HashLocationStrategy class for the location strategy instead of HTML5LocationStrategy. Don’t forget to import the provide function before.

import {provide} from 'angular2/core';

(...)

bootstrap(ApisparkApp, [
  ROUTER_PROVIDERS, HTTP_PROVIDERS,
  provide(LocationStrategy, {useClass: HashLocationStrategy}
]);

The last step consists of specifying where the component will be displayed. This will be done at the level of the component where routes are defined using the router-outlet core component. To be able to use it, don’t forget to import the ROUTER_DIRECTIVES array and to specify them within the directives attribute of our component.

import { Component } from 'angular2/core';
import { RouteConfig, ROUTER_DIRECTIVES } from 'angular2/router';

@Component({
  selector: 'apispark-app'
  template: `
    <router-outlet></router-outlet>
  `
  ,
  directives: [ ROUTER_DIRECTIVES ]
})
@RouteConfig([
  (...)
])

export class ApisparkApp {
}

Of course the content of the template could contain more elements but to keep things simple, we only specify the router-outlet component.

Now you need to define each component involved in the previous routes. Let’s start with company list.

Displaying a list of companies

To display the list of companies, we will create a new component through a class named CompanyList. That’s the name we used in the routing configuration. For a start, we hard-code the list of companies to display. We will see later how to get this list from a Web API. The basic frame of the component is very similar to the previous one of the main component.

@Component({
  selector: 'company-list'
  template: 
    (...)
})
export class CompanyList {
  public companies: Company[];

  constructor(private router: Router) {
    this.router = router;
    this.companies = (...)
  }

  selectCompany(company: Company) {
    (...)
  }
}

Within the associated template, we can leverage the ngFor built-in directive. Don’t forget to prefix the directive with an asterisk (*). The latter tackles template elements and corresponds to a shortcut that avoids you writing the whole template element. The associated expression defines the list to iterate over, as well as the local variable name, prefixed by the # symbol for the current element.

<ul>
  <li *ngFor="#company of companies">{{company.name}}</li>
</ul>

To display details about a specific element in the list, we can wrap the company name with an a element and add a click event on it. To do that, simply add a click attribute surrounded by parentheses. When a click event occurs, the associated expression will be executed. Here’s the selectCompany method of the component:

<ul>
  <li *ngFor="#company of companies"><a href="#" (click)="selectCompany(company)">{{company.name}}</a></li>
</ul>

The selectCompany method simply tells the injected router to reach the view for details. Don’t forget to return false at its end to prevent from propagating the event to the a element. As parameters of the navigate method, we need the view name but also some attributes. In our case, they correspond to the identifier of the company we want to show.

selectCompany(company: Company) {
  this.router.navigate( [ 'Details', { id: company.id }] );
  return false;
}

That’s all for the first part of this article. We saw here how to start with Angular 2 to be able to display a list of elements. We will see in the next part of the article some more advanced features like how to leverage a data service and link components to a RESTful backend.

The source code is available in the following Github repository: https://github.com/restlet/restlet-sample-angular2.

CTA_Free Trial_2