Pluralsight Logo
Author avatar

Nikola Brežnjak

Author badge Author

Getting started with Angular 2 by building a Giphy search application

Nikola Brežnjak

Author BadgeAuthor
  • May 3, 2017
  • 26 Min read
  • 60,992 Views
  • May 3, 2017
  • 26 Min read
  • 60,992 Views
Front-End JavaScript

Introduction

In this guide, you will build a Giphy search application to learn Angular 2's basics and some advanced skills.

For those who come from the Angular 1 world, I will draw comparisons throughout the tutorial. Nevertheless, you don't need to be familiar with Angular 1. However, you do need to be familiar with JavaScript to understand this tutorial. There are plenty of resources online to get you started, even free books.

Objective

This guide hopes to teach you how to use Angular CLI to build an Angular 2 application for searching Giphy's gifs by using their API. The main points behind Angular 2 are taught along the way.

Angular 2

You've all heard the news; Angular 2 is/will be the next best thing in the web and mobile (with Ionic framework) development world. You've waited for some time for it to become stable, and now as the release date approaches (RC4 is already out as of this writing) you're finally ready to learn its basics and figure out its nuances.

Now, at this point you may still say:

Yeah, sure, but I've heard that React/Ember/NameYourPoison is way better

I will answer this question similarly as I did in a conference talk I gave a few months ago:

Please just stop with the analysis paralysis already. Pick a framework (any framework for that matter) that the community is using, use it, and see how far it gets you. All these talks about X being slow or Y being better just make no sense until you try it yourself for your use case and preference.

With all this said, fasten your seatbelts, take a venti (or trenta) sized cup of coffee, and let's go!

Demo app

As said in the Objective paragraph, we'll build an application for searching (and showing) gifs from the Giphy website by using their API. In the end, we'll also deploy our app to Github pages.

You can try the app here, and you can fork the complete source code on Github.

Prerequisites

Make sure that the following tools are installed:

Transitioning from Angular 1?

So, you've skimmed a few lines of this new shiny Angular 2.0 thing, and you were like

Trust me; I share your pain. When I first looked at it, I thought I was losing my grip. I was pretty comfortable with how Angular 1 did things and this seemed so different.

However, now a converted man, I'll tell you the same thing you've probably heard before:

Angular 2.0 is much better than its predecessor.

Adjusting to new technology is difficult, but it may prove necessary. Plus, once you become familiar with it, you won't remember why you didn't like it in the beginning.

By the way, there is a fast, easy method of migrating apps from Angular 1s. If you want to get into the details of how to migrate app to Angular 2, start here.

Angular CLI

Setting up an Angular 2 application (at least at this point in time) from the ground up is actually a lot of work in terms of installing and configuring settings.

Folks at Ember had one great advantage; a tool called ember-cli, that bootstraps the application and helps with some common project operations and scaffolding.

Sure, we had Yeoman and its Angular generators, but it did not become a widely-known convention, and it definitely wasn't a defacto tool like Ember. Proof that Ember CLI is a way ahead is that Angular-CLI's Github page says:

Prototype of a CLI for Angular 2 applications based on the ember-cli project.

Now, enter Angular CLI. Although this project is currently in beta, we can use it to:

  • Create a scaffolded app with proper directory structure and included tests, with one simple command (ng new)
  • Generate components, routes, services and pipes (the CLI will also create simple test shells for all of these)
  • Put your application in production (ng serve) easily
  • Deploy the app via GitHub Pages (ng github-pages:deploy)
  • Run unit tests or your end-to-end tests
  • Execute the official Angular2 linter (ng lint)
  • ...

Cool, this got us excited, as now we'll have the folks from Ember becoming converts (teasing, don't judge me :)). Let's move onto installing Angular CLI.

Installing angular-cli

It's as simple as running:

npm install -g angular-cli

You can confirm that the installation went well if you run:

ng --help

and get a bunch of output and help on various angular cli commands.

Just for reference (in case you follow this tutorial at a later stage and something is not the same as I output it here), my version (ng --version) as of this writing is angular-cli: 1.0.0-beta.9.

Starting a new app with angular cli

We'll call our app, originally, GiphySearch. So, let's start a new app using angular-cli:

ng new GiphySearch

You should get an output similar to this:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
# nikola in ~/DEV/Angular2 [13:57:55]
→ ng new GiphySearch
Could not start watchman; falling back to NodeWatcher for file system events.
Visit http://ember-cli.com/user-guide/#watchman for more info.
installing ng2
  create .editorconfig
  create README.md
  create src/app/app.component.css
  create src/app/app.component.html
  create src/app/app.component.spec.ts
  create src/app/app.component.ts
  create src/app/environment.ts
  create src/app/index.ts
  create src/app/shared/index.ts
  create src/favicon.ico
  create src/index.html
  create src/main.ts
  create src/system-config.ts
  create src/tsconfig.json
  create src/typings.d.ts
  create angular-cli-build.js
  create angular-cli.json
  create config/environment.dev.ts
  create config/environment.js
  create config/environment.prod.ts
  create config/karma-test-shim.js
  create config/karma.conf.js
  create config/protractor.conf.js
  create e2e/app.e2e-spec.ts
  create e2e/app.po.ts
  create e2e/tsconfig.json
  create e2e/typings.d.ts
  create .gitignore
  create package.json
  create public/.npmignore
  create tslint.json
  create typings.json
Successfully initialized git.
⠸ Installing packages for tooling via npm
├── es6-shim (ambient)
├── angular-protractor (ambient dev)
├── jasmine (ambient dev)
└── selenium-webdriver (ambient dev)

Installed packages for tooling via npm.

After this command finishes, let's cd into the project and run it:

1
2
cd GiphySearch
ng serve

You should get ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# nikola in ~/DEV/Angular2/GiphySearch on git:master ● [14:05:03]
→ ng serve
Could not start watchman; falling back to NodeWatcher for file system events.
Visit http://ember-cli.com/user-guide/#watchman for more info.
Livereload server on http://localhost:49154
Serving on http://localhost:4200/

Build successful - 889ms.

Slowest Trees                                 | Total
----------------------------------------------+---------------------
BroccoliTypeScriptCompiler                    | 484ms
vendor                                        | 332ms

Slowest Trees (cumulative)                    | Total (avg)
----------------------------------------------+---------------------
BroccoliTypeScriptCompiler (1)                | 484ms
vendor (1)                                    | 332ms

Your browser should show you the string app works! when you visit the app on the link: http://localhost:4200/.

In case you're curious about the 'Could not start watchman' output above. You can learn more on the link. In short, the link tells you about using brew install watchman if you're on Mac.

Folder structure

Now, let's open this project in the editor of your choice (I'm using Sublime Text 3), and you should see something like this:

As I said, this is an introduction tutorial to get you running fast, so I won't be going into any specific details this time (this is up for some other posts), so here we'll only focus on the src folder. The contents of that folder should be something like this:

What is this TypeScript thing?

Now, you might be wondering, what are all these .ts files?

Well, these are TypeScript files, and even though you don't need to use TypeScript with Angular 2, probably everyone on this Earth does.

So, what is it? On their website they state that:

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

You may have already seen this image before:

From it, we can see that this TypeScript contains ES6 (EcmaScript6), which then again contains ES5 (EcmaScript5), which yet again means that TypeScript contains ES5.

Since most browsers today can't run ES6 or yet alone TypeScript, we use the so-called transpilers which turn our TypeScript or ES6 code into ES5 code which is a 'plain ol' JavaScript that you're most probably familiar with and that basically all of today's browsers understand.

Some of the features that TypeScript brings to the table are:

I won't go into details here; you can learn about each of them by clicking on the links. However, let's just take a look at a few things to get you started.

You now define variable as:

var myVar: string;

Notice that we defined the type of our variable using : string. This is new.

Similarly, you now have the ability to specify the return value type of the function:

1
2
3
function myFunc (msg: string): string {
    return 'I like to repeat what you said, therefore: ' + msg;
}

Just for reference, we have the following types:

  • string
  • number
  • array
  • enum
  • any
  • void

If you want to play with TypeScript on your own (in a separate project), you have to install it by running the following command:

npm install -g typescript

Then, you can write any TypeScript code, save it in a file, run it through the TypeScript compiler, and finally run the output of the TypeScript compiler with Node.

For a quick example, let's create a file named tsTest.ts and put the above function in it, along with a call of the function, such as console.log(myFunc('hello'));. Our file should look like this:

1
2
3
4
5
function myFunc (msg: string): string {
    return 'I like to repeat what you said, therefore: ' + msg;
}

console.log(myFunc('hello'));

Then run this file through the TypeScript compiler like this:

tsc tsTest.ts

Now you should see a tsTest.js file beside your tsTest.ts file, and now you can run it with node like this:

node tsTest.js

and as an output, you should get I like to repeat what you said, therefore: hello.


Adding content

Ok, so, let's add something to our app.

But where to start?

Well, one of the first things I do when I get to a project for the first time is look at the generated output. Then I try to find the strings corresponding to that output within the source code. To do this, I use Sublime's Search command. If you're using another editor, I'm sure your editor will have a similar feature for finding appropriate strings in source code.

So, if we search for the string app works!, you'll see the string is within the app.component.ts file (in the app folder). This file contains the following:

1
2
3
4
5
6
7
8
9
10
11
import { Component } from '@angular/core';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  title = 'app works!';
}

Imports

What do all the @ symbols mean?

Without knowing anything about that, we can see where we would change the app works! text. So, let's change that to Welcome to GiphySearch.

Ok, let's tackle what all this new code means here:

import { Component } from '@angular/core';

The import command defines which parts we'll import and use in our code. In our case, we're importing the Component from the @angular/core module.

Components

If Web development had its own newspaper or magazine, you would probably see headlines like:

Directives obsolete, Components lend sight into the future

All aboard with the Components

Components: why they're great, and why you should use them, and why they're going to change the world.

In short, components are the new directives, which, in case you're familiar with Angular 1, are the building blocks of your angular application.

Here's a sample component:

1
2
3
4
5
6
7
8
9
10
11
12
import { Component } from "@angular/core";

@Component({
  selector: 'awesome',
  template: `
      <div>
          Awesome content right here!
      </div>
    `
})

class Awesome { }

The Component Decorator (@Component) adds additional data to the class that follows it (Awesome), like:

  • selector - tells Angular what element to match
  • template - defines the view

The Component controller is defined by the Awesome class.

We'll be able to use this new tag (awesome) in our HTML like this: <awesome></awesome>, and once rendered to the user in the browser, it will be shown as Awesome content right here!.

You may have noticed that in this example we defined the template using backticks (`). Backticks in the template allow us to define multiline strings.

Even though there are some people who define the template within the @Component, I tend to avoid that and have the template's HTML defined in a separate file. This is also how angular-cli prefers it, so Q.E.D.

Adding input and button

Our basic application should have one input field and one button.

To do this, add the following code to the app.component.html file:

1
2
3
<input name="search">

<button>Search</button>

Actions

Having a simple search input field and a button doesn't help much. We want to click the button, and we want to output something to the console just to verify it's working correctly.

So, this is how we define a function that will handle button click in Angular 2:

<button (click)="performSearch()">Search</button>

But, now if you click this button you will get an error. That's because we haven't defined the performSearch function anywhere.

Let's do that now. In the app.component.ts file, add the following function definition inside the AppComponent class:

1
2
3
performSearch(): void {
    console.log('button click is working');
}

With this, we have defined the performSearch function, which doesn't accept any parameters and it does not return anything (void). Instead, it just prints button click is working to the console (open up your developer tools to access it).

Taking an input

What if we would like to print to the console the string that someone typed in the input field?

Well, first we need to add a new attribute to the input field:

<input name="title" #searchTerm>

The #searchTerm (a.k.a resolve) tells Angular to bind the input to the new searchTerm variable.

Then, we need to pass this variable in the performSearch function like this:

<button (click)="performSearch(searchTerm)">Search</button>

Finally, in the app.components.ts file change the performSearch function like this:

1
2
3
performSearch(searchTerm: HTMLInputElement): void {
    console.log(`User entered: ${searchTerm.value}`);
}

So, we added a new parameter to the function (searchTerm), which is of the HTMLInputElement type. And we used the backticks to output the string in the console.log. You should notice how we used ${} to output the variable inside the backticks. Because searchTerm is an object, we had to get its value by referencing its value property (${searchTerm.value}).

Giphy search API

Finally, we come to the cool part, and that is to fetch some data from the service and to show it in our app (in our case, we'll show images).

So, how do we get this API? Well, if you do a simple Google search for giphy api and open the first link you'll get the documentation for their API.

We need the search API. If you scroll a bit, you'll find the following link:

http://api.giphy.com/v1/gifs/search?q=funny+cat&api_key=dc6zaTOxFJmzC

Great, now we see what kind of a request we need to create to search Giphy's gif database for a certain term.

If you open this link in the browser, you'll see what the service returns. Something like:

In the next section, we'll cover retrieving this data from within our app.

Angular HTTP requests

I hope that this part will be improved in the future, but I have to share with you my pain in getting this to work properly. I've sifted through various StackOverflow answers to get this seemingly-easy task done.

In Angular 2, we always import the HTTP service from @angular/http module. The following command gets that done:

import { HTTP_PROVIDERS } from '@angular/http';

Now we can inject Http into our component.

So, let's translate this into our code. In the app.components.ts file, add the following code after the first import:

import { Http, Response } from '@angular/http';

Then, define two variables:

1
2
link = 'http://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=';
http: Http;

Then, add the constructor like this:

1
2
3
constructor(http: Http) {
    this.http = http;
}

And, finally, add this to the performSearch function:

1
2
3
4
5
6
var apiLink = this.link + searchTerm.value;

this.http.request(apiLink)
    .subscribe((res: Response) => {
        console.log(res.json());
    });

Just for reference, to put it all in one listing, the contents of the app.component.ts file should be:

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
import { Component } from '@angular/core';
import { Http, Response } from '@angular/http';

@Component({
    moduleId: module.id,
    selector: 'app-root',
    templateUrl: 'app.component.html',
    styleUrls: ['app.component.css']
})

export class AppComponent {
    title = 'Welcome to GiphySearch';
    link = 'http://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=';
    http: Http;

    constructor(http: Http) {
        this.http = http;
    }

    performSearch(searchTerm: HTMLInputElement): void {
        var apiLink = this.link + searchTerm.value;

        this.http.request(apiLink)
            .subscribe((res: Response) => {
                  console.log(res.json());
            });
    }
};

If you run this now, you'll get a No provider for Http! error. As mentioned, after some long searching, I made this work by adding the following import line to the main.ts file (in the app folder):

1
import { HTTP_PROVIDERS } from '@angular/http';

At the end of the same file, add bootstrap(AppComponent, [HTTP_PROVIDERS]);.

Now, the contents of the app.ts file should be:

1
2
3
4
5
6
7
8
9
10
import { bootstrap } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { HTTP_PROVIDERS } from '@angular/http';
import { AppComponent, environment } from './app/';

if (environment.production) {
  enableProdMode();
}

bootstrap(AppComponent, [HTTP_PROVIDERS]);

Now, if you run the app, enter something in the search box, and click the search button, you'll see something like this in your console log:

You can see that we're getting back the result object, and that in it's data property there are 25 objects, which hold information about the images that we want to show in our app.

But, how do we show these images in our application?

We see that the API call returns 25 images. Let's save this in some variable for later use:

giphies = [];

Let's store the results from the API call to this variable as well:

this.giphies = res.json().data;

Now, the contents of the app.component.ts file should be:

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
import { Component } from '@angular/core';
import { Http, Response } from '@angular/http';

@Component({
    moduleId: module.id,
    selector: 'app-root',
    templateUrl: 'app.component.html',
    styleUrls: ['app.component.css']
})

export class AppComponent {
    title = 'Welcome to GiphySearch';
    link = 'http://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=';
    http: Http;
    giphies = [];

    constructor(http: Http) {
        this.http = http;
    }

    performSearch(searchTerm: HTMLInputElement): void {
        var apiLink = this.link + searchTerm.value;

        this.http.request(apiLink)
            .subscribe((res: Response) => {
                  this.giphies = res.json().data;
                  console.log(this.giphies);
            });
    }
};

And, well, this is all great now, but we don't want to be logging out our objects to the console, we want to show them in our app.

To show the image, we need to position ourselves on the object images, then original, and finally on the url property.

Also, we don't want to just show one image but all of the images. We'll use Angular 2's version of the ng-for from Angular 1. It now looks like this:

<img *ngFor="let g of giphies" src="{{g.images.original.url}}">

For reference, here's the full listing of app.component.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
<h1>
  {{title}}
</h1>

<input name="search" #searchTerm>

<button (click)="performSearch(searchTerm)">Search</button>

<br>

<div *ngFor="let g of giphies">
    <img src="{{g.images.original.url}}">
</div>

At this point, if we take a look at the app and search for example for 'funny cats' we'll get this:

Although the result doesn't look sleek, our code does exactly what it's supposed to do. If you want it to look nicer, feel free to add more CSS in the app.components.css file.

Deploying to Github pages

Angular CLI had made things really easy for us, as all we have to do is run the following command:

ng github-pages:deploy

You should get an output similar to this:

1
2
3
4
5
# nikola in ~/DEV/Angular2/GiphySearch on git:master
→ ng github-pages:deploy
Built project successfully. Stored in "dist/".
Deployed! Visit https://hitman666.github.io/giphy-search/
Github pages might take a few minutes to show the deployed site.

However, in my case, this just wasn't working. When I opened the link I got the 404. After searching, I found this solution. But again, it didn't resolve the issue.

Then, I figured that I already have the Github pages repository after creating my Github page.

The following command may work for you. If it doesn't, then create your own Github pages, by following the official instructions. Then, in your Github pages repository, create a new folder (I called it giphy-search).

In the index.html file just change the base url to the name of your folder. In my case that's giphy-search:

<base href="/giphy-search/">

Then, copy the contents of the GiphySearch/dist folder to giphy-search folder.

Add new files, commit them, and push them:

git add .

git commit -m 'adding new project to Github pages'

git push origin master

Now you'll have your app accessible at yourusername.github.io/giphy-search. In my case, the link is http://hitman666.github.io/giphy-search/.

In case you would like to deploy this to your own server, just make sure you execute ng build and then copy the contents of the dist folder to your web server's proper folder. Also, don't forget about the proper base url setting.

Conclusion

In this tutorial, you learned how to get started with using Angular 2 by building an application for searching Giphy's gifs by using their API. You learned how using Angular-CLI helps remove the pain of setting everything up. You also learned about some new concepts like Components, and you wrote code in the new TypeScript language.

In the following tutorials we'll go into more detail, but this should give you enough to start and continue exploring on your own until next time.

Thank you for reading!

5