Enter Your Email Address to Watch This Lesson

Your link to unlock this lesson will be sent to this email address.

Unlock this lesson and all 985 of the free egghead.io lessons, plus get Angular 2 content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Consuming events as Observables in Angular 2

3:07 Angular 2 lesson by

In this video series we’ll take a look at Observables in Angular 2. We’ll figure out how they integrate with the http layer and how we can leverage their power to build a rock solid instant search with just a bunch of operators.

This first video walks you through the process of refactoring an existing solution to consume events from the template as Observables.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

In this video series we’ll take a look at Observables in Angular 2. We’ll figure out how they integrate with the http layer and how we can leverage their power to build a rock solid instant search with just a bunch of operators.

This first video walks you through the process of refactoring an existing solution to consume events from the template as Observables.

Avatar
Karstacian

If I call the subscribe in the search function will it not create a new subscription each time I call search?

Avatar
Creativestyle

It seems to me that there is a typing in : URLSerachParams (Search not Serach)

Avatar
Oscar

+1, would be nice to have a github repo to this post so it can be updated.
I am receiving no provider for connectionbackend! as an error with described code above

In reply to Creativestyle
Avatar
Corey

Hi, found the issue with the error you noted above, I was importing the HttpModule and needed to import the JsonpModule under the 'imports' property in @NgModule decorator.

In reply to Oscar
Avatar
sk29110

Is it possible to remove echo sound from the video. I didn't find it on other videos but this series have extra echoing.

In reply to egghead.io
Avatar
James

for brevity:

// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule, JsonpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { WikipediaSearchService } from './wikipedia-search.service';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    JsonpModule
  ],
  providers: [
    WikipediaSearchService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
In reply to Corey
Avatar
Kemal Yalcinkaya

URLSerachParams seems to be deprecated by the Angular team, FYI

Avatar
Angela

Hi, I'm new to Angular 2. I see JSONP is being used for HTTP GET call. Can JSONP be used for POST/PUT/DELETE calls? I got 403 error when doing PUT/DELETE calls with JSON. Any insights would be appreciated.

In reply to egghead.io
Avatar
Jacob

I'm learning ngrx and came across a similar problem for fetching data from the server and displaying. Here is the code for it: https://github.com/ngrx/example-app/blob/master/src/app/effects/book.ts

My question is why the ngrx example is done differently with just Observable and not Subject. I also posted a question in stack overflow at http://stackoverflow.com/questions/42596635/why-takeuntil-is-necessary-in-this-ngrx-example

In this video, we will learn how to consume events from our template as observables to build a richer user experience. Our starting point is a simple instance search with Wikipedia. As I type into the text box, we immediately see the results.

Building this kind of thing, we'll face issues such as sending too many requests or getting a lot of auto-responses. We would like to solve these issues in a functional reactive way using observables.

Before we get started with that, let's a quick look at the counter-implementation. We created our Wikipedia search service to perform Jsonp request against the Wikipedia API. We injected the Jsonp service and created a search method that takes string as a parameter.

Wikipedia-search.service.ts

import { Injectable } from '@angular/core';
import { URLSerachParams, Jsonp } from '@angular/http';

@Injectable()
export class WikipediaSearchService {
  constructor(private jsonp: Jsonp) { }

  search (term: string) {
    let search = new URLSerachParams();
    search.set('action', 'opensearch');
    search.set('search', term);
    search.set('format', 'json');

    return this.jsonp.get('http://en.wikipedia.org/w/api.php?callback=JSONP_CALLBACK', {search})
               .map(response => response.json()[1]);
  }
}

We then call out to the Wikipedia API to make the request. We also map the results of that. Our observable only carries an area of strings containing the results of our API request.

Let's open up our app.component.ts. As we can see, it consumes the WikipediaSearchService via dependency injection. It also exposes a method called search to be invoked from the template.

app.component.ts

import { Component } from '@angular/core';
import { WikipediaSearchService } from './wikipedia-search.service';

// application wide shared Rx operators
import 'rxjs/add/operator/map';

@Component({
  moduleId: module.id,
  selector: 'app-root',
  remplateUrl: 'app.component.html',
  styleUrls: ['app.component.css']
})
export class AppComponent {
  items:Array<string>;
  constructor(private service:WikipediaSearchService) {}

  search(term: string) {
    this.service.search(term)
                .subscribe(results => this.items = results);
  }
}

We also see that we are saving the results, our array, to an instance property called items. Since our service is using the map operator, we are importing it here for application-wide usage. Let's take a look at the template. It's a really basic markup, just enough to render an input box and the list.

app.component.html

<div> 
  <h2>
    <input (input)="seach($event.target.value)">
    <ul>
      <li *ngFor="let item of items">{{item}}</li>
    </ul>
  </h2>
</div>

We see that we listen for the input event on our input box. Whenever that happens, we invoke the search method that we created on our component. We have a simple unsorted list with list items generated by ngFor of our collection of items.

Now, that's all good. But in order to do things such as debouncing or deduplicating, we have to find a way to consume the changes of the input box as an observable of string. We can solve that using a Subject that we have to import from the rxjs library.

app.component.ts

import { Subject } from 'rxjs/Subject';

Notice that the build runs while I'm typing, which is why we sometimes see an error in the output. A Subject is an observable that we can subscribe to, but at the same time, we can also emit notifications on it. In a way, we can see it as a proxy between the actual event and an observable of that event.

We need to create a property of type subject of string. Let's call it term$. Some people use a dollar suffix to indicate that a variable is an observable. We use this convention here, too, but that's really just a convention that some people use, so feel absolutely free to ignore it.

Now that we have the Subject, we need to make sure to subscribe to emitted changes and invoke our search method from here. We can do that either in the constructor or in the OnInit hook. It would be a bit cleaner to do that in the OnInit hook, but for the purpose of this exercise, we can keep it here.

app.component.ts

export class AppComponent {
  items:Array<string>;
  term$ = new Subject<string>();
  constructor(private service:WikipediaSearchService) {
    this.term$.subscribe(term => this.search(term))
  }

  search(term: string) {
    this.service.search(term)
                .subscribe(results => this.items = results);
  }

So far, there's no one actually raising notifications on our Subject. Let's change our template to not directly invoke search, but call term$.next instead.

app.component.html

<div> 
  <h2>
    <input (input)="term$.next($event.target.value)">
    <ul>
      <li *ngFor="let item of items">{{item}}</li>
    </ul>
  </h2>
</div>

By doing that, we are forwarding the input event into our subject, and that's it. Our Subject still works the same way as before, but we are now proxying the user input through an observable, which is exactly what we need to proceed with our next refactoring.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?