Angular 2 — TwitchTV : Dynamic Search Result using Angular’s HTTP Service + RxJS Observables

This post will cover the generation of an interactive search result component using the Angular2 HTTP service. In our application we would like to be able to continue to interact with our page while HTTP requests are made via Twitch API calls and returned from the external server.

In this story you will need to follow the instructions and code yourself. At the end of this article our application will behave as shown!

twitch-search app

Before we create the component lets loosely cover the basics of dealing with synchronous and asynchronous requests.

Synchronous Request: A synchronous request blocks code execution causing your application to wait until a response is returned.

Asynchronous Request: An asynchronous request doesn’t cause your application to wait and allows other operations to be performed.

In our application making a synchronous API call would impede any further code from executing. The blocking of code execution means that the application does not continue any further until a response is returned. With asynchronous API calls we can leverage the fact that we are able to continue the execution of code without having to wait for a response to the request.

Angular2 deals with asynchronous code using RxJS Observables. In short, Observables allow us to emit an asynchronous stream of events to any subjects subscribed to it. The emitted asynchronous stream of data can then be functionally operated on to return a desired output.


Step#1 — Setup

To setup Angular2 you need to install the angular-cli package globally. This will give us the tools needed to create the basic file and folder structure needed to create our Angular2 app.

$ $ npm install -g @angular/cli

Once angular-cli has been installed globally we can go ahead and create our seed project in the project directory.

$ ng new twitch-search

Let’s briefly understand the folder structure and the files that we are interested in.

e2e:This folder is for end to end testing as the name suggests. If you want to incorporate end-to-end testing automation use this folder. For this app we will not be using this.

node_modules: This folder will contain all the installed dependencies listed in package.json. The package.json contains a starter-set of dependencies that are required by Angular2. Inside package.json there is a start script named ng serve. We can run run this script to boot up our deployment server at http://localhost:4200.

src: This is the main folder we will be using. It contains the app folder which contains all our code.

We will be using Bootstrap and its components to code the template. Head on over to https://www.bootstrapcdn.comand get the complete HTML bootstrap CSS. For simplicity’s sake, we will add this external link to app.component.html under the src/app folder.

app.component.html

Step #2 — Model

Under the directory src/app create a folder and name it searchbox . We will be creating the necessary files under this folder.

Create the file streamresult.model.ts under src/app/searchbox. The streamresult class will serve as the model of our data that is requested from Twitch API calls. Add the following fields and a constructor in the class.

streamresult.model.ts

The idea behind obj?:any in our constructor is that it allows us pass in an object containing our keys when a StreamResult object is created.


Step #3 — Service

In Angular2 we can create components and nest components together with selectors. In order to share common functionalities over these components we will need to create a service to handle the requested external data.

Angular’s dependency injection allows our components to inject our service in its constructor when its needed (more on this later..).

We will be using the following endpoint provided by Twitch’s API in order to retrieve the data we desire.

Go ahead and create the service class streamresult.service.ts under src/app/searchbox .

streamresult.service.ts

This class is decorated with the @Injectable()decorator and is used with the dependency injector. The service contains the search method that makes HTTP requests and receives HTTP responses back from the server asynchronously using Observables. In order to achieve this we add the necessary imports at the top of the class.

To use the HTTP service we inject an instance of http in our service constructor.

The search method takes a parameter which will be used in our component to pass in dynamic keywords every time our search box is updated. Next, http.get will fetch data using our constructed query consisting of the API key, keyword, and the number of objects returned by the array.

The return value of http.get is of type Observable. This value is then operated on by the map operator. The map operator will return the response in the form of API data as JSON and the catch operator will generate an observable that terminates with an error. Notice that by calling <any>response.json() we are omitting the need for strict type checking.

Array of stream objects matching the search query

Invalid client id message returned by catch operator

Lets have a more detailed look at the actual map operator. The map operator will convert the response values into a stream of objects that is then iterated on and converted into a streamResult object. It is important to realize here that the output of the map operator is an observable. We need to subscribe to this observable in order to extract a result.

Finally, we will need to add streamresultService to the provider array found in app.module.ts under src/app. The purpose of this is to notify Angular to create a new instance of the service when AppComponent is created. This service is then used by each component including its nested components.

app.module.ts

In the next section we will be creating the components needed in order to subscribe to the result and display the view.


Step #4 — Components

Angular2 places a strong emphasis on components. A typical application is made up of a tree of components starting from the root and scaling down to it’s child components. We will create our first component searchresult.component.ts under src/app/searchbox.

searchresult.component.ts

A couple of things to note here. The @Component decorator is used to indicate that the class at is a component containing the appropriate selector, template, and style. Again, for the sake of demonstration we will keep the the HTML and CSS inline within the component itself.

The@Input decorator defined in the class is responsible for passing data into the component itself. We have defined result to be of type Streamresult and thus we are able to use interpolation to display data to the component.

The next component we will create will display the search box and emit events based on the results. Lets create streamresultsearchbox.component.ts under src/app/searchbox. I will be breaking up the code in order to explain key concepts.

The template is a very simple search box to key in search results.

streamresultsearchbox.component.ts
streamresultsearchbox.component.ts

In the constructor of our class we have injected a StreamresultService instance and an instance of ElementRef in order to be able to access the underlying native DOM element.

The component we have created is a child component and will be able to pass values by including an@Output decorator on a variable of type EventEmitter. We have set two variables loading and result to capture the values of the custom events that are fired out.

Note that in the constructor we have implemented the OnInit interface. Component instances have a lifecycle as they are created, modified or destroyed. One of the lifecycle hook interfaces in the core angular library is the OnInit interface. Implementing this interface means we need to implement its hook method ngOnInit(). Angular will call this method shortly after the component has been created.

Next, lets fill out the ngOnInit() method. We would like this method to be called when the component is created and as such, a return value is not needed. Let us understand very carefully what is going on in the following block of code.

streamresultsearchbox.component.ts

Observable.fromEvent is a very flexible event converter and will convert keyup events into an observable stream(notice that the first argument this.el.nativeElement is the native DOM element that this component is attached to). The stream is then piped to a map operator which extracts the value of the keyup input(our query). The filter operator then filters the stream to store values that are not empty. debounceTime will set a time span of 200ms before another value is emitted from the source observable. The do observable will allow us to perform operations on the side. The operation we are performing is emitting true from the EventEmitter object to enable loading. The stream is then sent to the map operator to be processed by our search method defined in our service. The switch observable will consider the higher order Observable into a first-order Observable. This means that previous events are discarded and the most recent projected Observable is considered. Finally, the subscribe operator will act upon the search on a success, error, and completion condition. In each of these cases we can then disable loading as the result has been handled by the subscriber. Only in the success condition do we emit our result back to the components output event handler.

We will now create the parent component by creating twitchsearchcomponent.component.ts under src/app/searchbox. The parent component will utilize the selectors defined in the previous components.

twitchsearchstream.component.ts

Remember that the my-searchbox selector was previously defined inside StreamresultsearchboxComponent. Inside the selector tag there are two specific events that are emitted from the component. These two events are (loading)="loading=$event" and (results)="updateResults($event)". When StreamresultsearchboxComponent emits a loading event the variable is set within the value of $event. Likewise, when a results event is emitted updateResults() is called with the value of $event . This has the effect of updating our components results instance variable.

The search-result selector was previously defined in SearchComponent. SearchComponent uses the @Input property result in order to retrieve a Streamresult object to display in its view. The search-result selector utilizes the ngFor directive to iterate through an array of Streamresult objects to bind an individual result object to display.

Now that we have completed coding our components section we will need to wire them to app.module.ts.

app.module.ts

Additionally, we will need to add the selector tag twitch-search from the TwitchsearchstreamComponent and place it inside app.component.html. The AppComponent is the root component of this application.

app.component.html

Finally we’re done! ..load up the dev server and run your application!