Building a Giphy Search Application in Angular 2
Sep 27, 2018 • 13 Minute Read
Introduction
The focus of this guide is to build an Angular 2 application for searching Giphy's gifs by using their API. For more information about transitioning from Angular 1 to Angular 2 and setting up an Angular application, read my previous guide: Getting Started with an Angular 2 Application.
Adding Content
We want to add something to our app but where to start? One of the first things I do when I start a project is to 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, it will likely have a similar feature for finding appropriate strings in source code.
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:
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!";
}
We can see where we would change the app works! text. So, let's change that to Welcome to GiphySearch.
Imports
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, Why You Should Use Them, and Why They're Going to Change the World
In short, components are the new directives, which are the building blocks of your angular application.
Here's a sample component:
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!.
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:
<input name="search">
<button>Search</button>
Actions
Having a simple search input field and a button doesn't help much. We want to be able to click the button and we want to output something to the console, to verify it's working correctly.
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. In the app.component.ts file, add the following function definition inside the AppComponent class:
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. To access this, open up your developer tools to access it.
Taking an Input
What if we would like the string that someone typed in the input field to print to the console? 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:
performSearch(searchTerm: HTMLInputElement): void {
console.log(`User entered: ${searchTerm.value}`);
}
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. 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: fetching some data from the service and showing it in our app. In our case, we'll show images.
How do we get this API? 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 search link.
Now we can see what kind of a request we need to create to search Giphy's gif database for a certain term. If you open the above link in the browser, you'll see what the service returns. Something like:
Next, we'll retrieve this data from within our app.
Angular HTTP Requests
In Angular 2, we always import the HTTP service from @angular/http module. The following command will do this:
import { HTTP_PROVIDERS } from '@angular/http';
Now we can inject Http into our component.
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:
link = "http://api.giphy.com/v1/gifs/search?api_key=dc6zaTOxFJmzC&q=";
http: Http;
Then, add the constructor like this:
constructor(http: Http) {
this.http = http;
}
Finally, add this to the performSearch function:
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:
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. I made this work by adding the following import line to the main.ts file (in the app folder):
import { HTTP_PROVIDERS } from "@angular/http";
At the end of the same file, add bootstrap(AppComponent, [HTTP_PROVIDERS]);.
The contents of the app.ts file should be:
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]);
When you run the app, enter a value into 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. In its 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:
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);
});
}
}
This is working 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.
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:
<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 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:
# 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.
The following command may work for you. If it doesn't, 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 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 https://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 guide, 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 and some new concepts like Components.
Thank you for reading!