Reputation: 925
I'm using Angular v4 and I want to add the ability to search by name, so I have created an service that allow to get list of movies:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Movies } from '../models/movies';
import { environment } from '../../../environments/environment';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
@Injectable()
export class SearchService {
constructor(private http: Http) { }
searchMovie(query: string): Observable<Movies> {
return this.http.get(environment.api.baseUrl + environment.api.searchMovie.uri + "?query=" + query)
.map((res:Response) => res.json() as Movies) // Process the success response object
.catch((error:any) => Observable.throw(error.json().errors || 'Server error')); // Process the error response object
}
}
This service is very simple, because send search terms to server and return a Observable. After this is my html, I'm using reactive form:
<section class="search-section">
<div class="container">
<div class="row">
<div class="col-xs-12">
<form class="form-search" [formGroup]="searchForm" novalidate>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon1"> <span class="glyphicon glyphicon-search" aria-hidden="true"></span> </span>
<input type="text" id="key" class="form-control" aria-describedby="basic-addon1" placeholder="Search for a movie..." formControlName="key">
</div>
</form>
</div>
</div>
</div>
</section>
Now this is my component:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from "@angular/forms";
import { Movies } from '../../models/movies';
import { Movie } from '../../models/movie';
import { SearchService } from '../../services/search.service';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/Rx';
@Component({
selector: 'search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss']
})
export class SearchComponent implements OnInit {
private searchForm: FormGroup;
private searchTerms = new Subject<string>();
private errorMessage: string;
private matchedMovies: Array<Movie> = [];
constructor(private fb: FormBuilder, private searchService: SearchService) {
this.createForm();
}
createForm(): void {
this.searchForm = this.fb.group({
key: ['']
});
// Check the changes
this.searchForm.valueChanges
.debounceTime(300)
.distinctUntilChanged() // ignore if next search query is same as previous
.switchMap(query => this.searchService.searchMovie(query.key))
.subscribe(
(result) => {
console.log(result);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
},
() => {
console.log("onCompleted");
});
}
ngOnInit() { }
}
When I search a movie, it works very well but when the user send a empty string I obtain 422 error from server (it's correct) but after this error the subscribe not working. I expect that it should work... This a quickly and simple plunker: http://plnkr.co/edit/Apb3x30Fbggpw4FsEAwJ?p=preview Thanks!
Upvotes: 3
Views: 9401
Reputation: 16540
You are not catching the error thrown by this.searchService.searchMovie(query.key)
You should catch the error or filter the input value before sending it to the backend.
example catch:
this.searchField.valueChanges
.debounceTime(400)
.switchMap(term => this.searchService.search(term).catch(e=>Observable.empty()))
.subscribe(result => {
console.log(result);
});
example filtering:
this.searchField.valueChanges
.debounceTime(400)
.filter(term=>term && term.trim().length > 0)
.switchMap(term => this.searchService.search(term)))
.subscribe(result => {
console.log(result);
});
Or even better, you can use both methods :)
here is your plunker edited.
Upvotes: 3
Reputation: 2131
You just need a catch:
search(term: string) {
return this.http.get("https://api.themoviedb.org/3/search/movie?api_key=fed69657ba4cc6e1078d2a6a95f51c8c&query=" + term)
.map(response => response.json())
.catch(error => '')
}
Here's the updated plunker: http://plnkr.co/edit/j1ggvND1wBYipbkZVOv2?p=preview
Basically the catch allows us to safely recover from the api error whereas without the catch the app breaks.
Upvotes: 1