Over a million developers have joined DZone.

First Steps With Angular 2: Eight Cool Features

The author takes us through some features including Pipes and Observables, with examples in TypeScript.

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

I've been doing some work the last couple of weeks with Angular 2. I really like it. Not just because it uses TypeScript, but also because it feels really natural and straightforward while working with it. No more string-based dependency injection, or strange digest cycle stuff—it just seems to work. This last week I've migrated our beta-13 Angular app to the latest rc-1, and used that to keep track of the fun and easy stuff Angular 2 provides. Note though that the application we're developing isn't really that complex, so I can only assume we'll run into more complex Angular 2 features in the near future. For now though, let me share some general tips and tricks we've encountered thus far (in no particular order). Oh, all examples are in TypeScript, since after using that, I really don't want to go back to plain old JavaScript (POJS?).

1. Pipes for Formatting

If you need to format some output string, in the old Angular version you used Filters. In Angular 2, though, the name of filters have changed and they are now called pipes. Using pipes is very easy and only takes a couple of steps to get working. First, you need to define a pipe:

import {Pipe} from '@angular/core';
import {FormatUtils} from '../utils/formatUtils';

@Pipe ({
  name : "humanReadableNumber"
})
export class HumanReadableNumber {

  transform(value: any) {
    // converts a size to something human readable
    return FormatUtils.humanSize(+value);
  }
}

Image title

Now that we've got a pipe we can import it in our component, and use it to format a value in our page. We import it like this, and add it to the pipes property:

import {Component} from '@angular/core';
import {CORE_DIRECTIVES} from '@angular/common';
import {HumanReadableNumber} from '../../../shared/pipes/humanReadablePipe'

@Component({
templateUrl: 'some-template.html',
  directives: [CORE_DIRECTIVES],
  pipes: [HumanReadableNumber]
})
export class SomeCmp {
  ...
}

And, using it in our code is just as simple:

<div class="col-sm-3">
  <span class="text-red">{{failureCount | humanReadableNumber}}</span>
</div>

The cool thing is you can chain pipes together, and of course also create parameterized pipes. The official documentation for pipes can be found here: https://angular.io/docs/ts/latest/guide/pipes.html

2. HTTP Is Easy to Use

You can't have a web application without making some HTTP calls to pull in data. With Angular 2 this is surprisingly easy. Just inject the **http** component, pass in the headers and parameters, and you get back an observable. As soon as you subscribe to the observable, the call will be executed, and you can easily use the functions provides by rx.js to transform the response (see next tip):

private getSomeData(timePeriod: TimePeriod): Observable<any> {

  let headers = new Headers();
  headers.append('Content-Type', 'application/json');

  // handle the today case differently, since we need to go to start of day
  let [from, to] = (timePeriod.name === Configuration.timePeriod.today.name)
    ? [moment().utc().hours(0), moment()]
    : [moment().subtract(timePeriod.amount, timePeriod.period), moment()];

  // setup and add the query parameters
  let params = new URLSearchParams();
  params.set('environment', 'test');
  params.set('interval', timePeriod.period);
  params.set('from', from.toISOString());
  params.set('to', to.toISOString());

  return this.http.get('http://the.url', { headers: this.getHeaders(), search: params })
    .map((res: any) => res.json());
}

And the result is an observable, which can be consumed like this:

someService.getSomeData(period).subscribe((json: any) => ({// do something with the json}));

The official documentation for HTTP can be found here: https://angular.io/docs/ts/latest/guide/server-communication.html

3. Observables Are Really Cool

In Angular 1, when communicating over HTTP or doing stuff asynchronously, you would use promises. In Angular 2, promises have been replaced with Observables. Without going too deep into what Observables are, in short they provide a way to subscribe to a sequence of events and act whenever the observable emits a new event. The really cool thing is that you can apply all kinds of operations and transformations on the events before they are processed by a subscriber. You can, for instance, map it to a domain object, group multiple events together, and much, much more (see the rx.js documentation for all the options: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html)

The easiest example of an Observable is when you want to do an HTTP request in Angular 2. Instead of working with promises, you now do something like this:

import {Http} from '@angular/http';
import {Inject} from '@angular/core';
import {Headers} from '@angular/http';

export class SomeService {

  constructor(@Inject(Http) private http: Http) {};

  getPerson() : Observable<Person> {
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');

    return this.http.get('http://the.url.endpoint', {headers})
      .map(res => res.json())
      .map(res => new Person(res.name, res.age));
  }
}

As you can see, the result is an Observable . We can now use this Observable very simply like this:

import {Component} from '@angular/core';
import {Person} from '../shared/domain';
import {SomeService} from 'some-service';

@Component({
  templateUrl: 'someTemplate.html'
})
export class AnotherCmp {

  public person: Person;

  constructor(private someService: SomeService) {
    someService.getPerson().subscribe((person) => (this.person = person));
  }
}

We subscribe to the observable. When we do this, the HTTP call will be made, and when it returns, we just assign the response to a public variable. Another feature of Observables we use is to wait for multiple calls to finish before sending the message to a subscriber. This uses the forkJoin function provided by RxJS.

public getMonthlyInfo(): Observable<MonthData[]>  {
  let observables: Observable<MonthData>[] = [];

  // create the observables for the different calls
  // and add them to the observables array
  ...

  // Intellij throws a false error: https://youtrack.jetbrains.com/issue/WEB-20992
  // this returns another observable, which returns an array of results from the
  // observables we passed in to the forkJoin
  return Observable.forkJoin(observables);
}

And this is just touching upon the surface of what is possible with Observables. On a side note, if you prefer to work with Promises, you can use the *toPromise* function on an observable to turn it into a promise.

4. Start With Angular 2 Seed

Maybe I should have added this as the first tip, but setting up a build environment using gulp systemJS (or webpack) can be a bit of a hassle. Luckily though, there is an easy way to get started using Angular seed. There are multiple Angular seeds available, but I use this one: https://github.com/mgechev/angular2-seed. It provides a systemJS / gulp based seed setup, including all kinds of nice features. Getting started with it, is also very trivial:

git clone --depth 1 https://github.com/mgechev/angular2-seed.git
cd angular2-seed
# install the project's dependencies
npm install
# watches your files and uses livereload by default
npm start
# api document for the app
npm run build.docs

# dev build
npm run build.dev
# prod build
npm run build.prod

If you want to use it as the base for your own project, it might be good to run the following git commands after cloning the repository, to point it to your own repository / project:

rm -rf .git
git init
git remote add origin https://giturl.of.your.project.git

5. Intercept Requests for Authentication

One of the first things I wanted to add to our application was a way to check whether a user was logged in. I was looking for global filters and stumbled upon this example: https://github.com/auth0-blog/angular2-authentication-sample. This shows how to use a RouterOutlet to check for certain conditions, before handling the request. Basically, what you do is, you define a custom RouterOutlet:

From (https://github.com/auth0-blog/angular2-authentication-sample/blob/master...):

import {Directive, Attribute, ViewContainerRef, DynamicComponentLoader} from '@angular/core';
import {Router, RouterOutlet, ComponentInstruction} from '@angular/router-deprecated';
import {Login} from '../login/login';

@Directive({
  selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
  publicRoutes: any;
  private parentRouter: Router;

  constructor(_viewContainerRef: ViewContainerRef, _loader: DynamicComponentLoader,
              _parentRouter: Router, @Attribute('name') nameAttr: string) {
    super(_viewContainerRef, _loader, _parentRouter, nameAttr);

    this.parentRouter = _parentRouter;
    // The Boolean following each route below
    // denotes whether the route requires authentication to view
    this.publicRoutes = {
      'login': true,
      'signup': true
    };
  }

  activate(instruction: ComponentInstruction) {
    let url = instruction.urlPath;
    if (!this.publicRoutes[url] && !localStorage.getItem('jwt')) {
      // todo: redirect to Login, may be there a better way?
      this.parentRouter.navigateByUrl('/login');
    }
    return super.activate(instruction);
  }
}

And this allows you to check certain conditions before normally processing the request, or passing it on. I can explain how it works here, but just look at the GitHub repository which will do a much better job.

6. Directives Are Very Easy to Write

In Angular 2, the distinction between controllers and directives is removed. A directive is just a simple component, where some of its values are populated when the component is instantiated. For instance, a simple component that wraps one of the great https://github.com/valor-software/ng2-charts charts looks like this:

import {Component, Input} from '@angular/core';
import {CORE_DIRECTIVES} from '@angular/common';
import {CHART_DIRECTIVES} from 'ng2-charts/ng2-charts';
import {DecisionNodeSummary} from '../../../shared/domain/dagSummary';

@Component({
  selector: 'dag-decnode-graph',
  templateUrl: 'decisionnode-graph.html',
  directives: [CHART_DIRECTIVES, CORE_DIRECTIVES]
})
export class DagDecNodeGraph {

  public title = "";

  @Input()
  set nodeSummary(nodeSummary: NodeSummary) {
    this.routingStatusChartData = [nodeSummary.falsePath, nodeSummary.truePath];
    this.title = nodeSummary.name;
  };

  public routingStatusChartLabels: string[] = ['false', 'true'];
  public routingStatusChartType: string = 'doughnut';
  public routingStatusChartLegend: boolean = false;
  public routingStatusChartData: number[] = [0, 0];
  public routingStatusChartOptions: any = {};

  constructor() {
  }

}

And the relevant template:

<div class="col-md-4">
  <h4 style="text-align: center">{{ title }}</h4>
  <base-chart class="chart"
              [data]="routingStatusChartData"
              [labels]="routingStatusChartLabels"
              [legend]="routingStatusChartLegend"
              [chartType]="routingStatusChartType"></base-chart>
</div>

Nevermind the model which is passed in, but this is basically all you need to do to define a directive. To use this directive in a page you just do something like this:

<div *ngFor='let node of nodes'><dag-decnode-graph [nodeSummary]="node"></dag-decnode-graph></div>
</div>

How easy is that! No more specific JavaScript or custom functions. Just a simple component, just like all the other components.

7. TypeScript: Domain Objects Are Cheap and Easy, Type Everything.

I couldn't write this without at least mentioning TypeScript. I really like TypeScript. I come from a Java and Scala background and am used to having compile-time typechecking (and using IDEs to autocomplete some stuff). With Typescript, this also becomes available to Angular, and it works really great. What makes it even better is that creating basic domain objects is really easy and quick:

export class Person {
  constructor(public name: number, public age: number) {}
}

And you can easily access the public properties and hide the private properties. It even supports default values. It isn't quite up to Scala case classes yet, but it is a great way of defined a good domain model in your frontend applications. This combined with the **map** function of the **Observable** makes it very easy and convenient to use these domain objects throughout your application.

8. Use jQuery

In many cases, there isn't a big need for jQuery in Angular projects. However, there is a big ecosystem of great jQuery based components and libraries that will come in handy. While using jQuery in Angular 2 isn't that difficult, getting the TypeScript compiler to compile your code when including jQuery in your dependencies might be harder. When you include jQuery you'll quickly run into an error message something like this:

Subsequent variable declarations must have the same type.  
Variable '$' must be of type 'cssSelectorHelper', but here has type 'JQueryStatic'.
Web\Scripts\typings\jquery\jquery.d.ts   3936

Basically, there are two different libraries claiming the $ name. This can be quickly solved by replacing the last couple of lines from the **jquery/index.d.ts** to this:

interface JQuery {
    // add additional functions you might want to expose from other libraries
    // that append the jquery object
    chosen(options?:any):JQuery;
    bootstrapTable(...options:any[]):JQuery;
}

declare module "jquery" {
    export = JQuery;
}
declare var jQuery: JQueryStatic;

Now you can use the jQuery library like this in code:

declare var jQuery:JQueryStatic;

...
// do whatever you want, just use jQuery instead of $
jQuery('.elem')

While this works, you'll notice that you have to repeat this process after each npm install or whenever you add a new library. Luckily you can override the typings that are retrieved when doing an **npm install**. So, to permanently apply these settings, save the typings to a separate directory and change the jQuery entry in the **typings.json** file to this:

"jquery": "file:overrides/typings/jquery/index.d.ts",

This points to our own custom jQuery typings file in a separate directory. Finally, to get everything to work, also update the tsconfig.json file to exclude this file or else you'll get duplicate definitions errors:

"exclude": [
  "node_modules",
  "dist",
  "typings/browser.d.ts",
  "typings/browser",
  "src",
  "overrides"
]

Conclusions

This is just a quick set of observations from a couple of days of intensive Angular 2 development. My main conclusion, though, it that it really is fun doing front-end development with Angular 2. It might be because of TypeScript, but so far it feels like a really great, well-thought-out framework. It just works and a lot of the annoying things from Angular 1 have been solved.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
angular 2.0 ,angularjs ,typescript

Published at DZone with permission of Jos Dirksen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}