【问题标题】:Angular v4: Search by name with observableAngular v4:使用 observable 按名称搜索
【发布时间】:2017-12-16 01:32:11
【问题描述】:

我正在使用 Angular v4,我想添加按名称搜索的功能,所以我创建了一个允许获取电影列表的服务:

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
  }

}

这个服务非常简单,因为将搜索词发送到服务器并返回一个 Observable。 在这是我的 html 之后,我使用的是响应式表单:

<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>

现在这是我的组件:

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() { }

}

当我搜索一部电影时,它运行良好,但是当用户发送一个空字符串时,我从服务器收到 422 错误(这是正确的),但在此错误之后,订阅不起作用。 我希望它应该工作...... 这是一个快速而简单的插件: http://plnkr.co/edit/Apb3x30Fbggpw4FsEAwJ?p=preview 谢谢!

【问题讨论】:

    标签: angular typescript rxjs observable angular2-forms


    【解决方案1】:

    你只需要一个捕获:

      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 => '')
      }
    

    这是更新后的插件:http://plnkr.co/edit/j1ggvND1wBYipbkZVOv2?p=preview

    基本上,catch 允许我们安全地从 api 错误中恢复,而没有 catch 应用程序会中断。

    【讨论】:

    • 它有效,但我有一个问题......这样我不能使用从服务器返回的错误,因为你写了.catch(error => '')。我更新了 plunker,现在不工作了。 plnkr.co/edit/quDPGxkvOIgjsF9zNiBm?p=preview。谢谢。
    【解决方案2】:

    你没有捕捉到this.searchService.searchMovie(query.key)抛出的错误

    您应该在将输入值发送到后端之前捕获错误或过滤输入值。

    示例捕获:

    this.searchField.valueChanges
          .debounceTime(400)
            .switchMap(term => this.searchService.search(term).catch(e=>Observable.empty()))
            .subscribe(result => {
                console.log(result);
            });
    

    过滤示例:

    this.searchField.valueChanges
          .debounceTime(400)
          .filter(term=>term && term.trim().length > 0)
            .switchMap(term => this.searchService.search(term)))
            .subscribe(result => {
                console.log(result);
            });
    

    或者更好的是,你可以同时使用这两种方法:)

    这是您编辑的plunker

    【讨论】:

    • 好的,它可以工作,但我有一个问题...如何管理从服务器返回的错误?因为当我获得错误时,我想在自动完成后销毁列表(我的用例是自动完成输入)。谢谢!
    • @Ragnarr 您可以将销毁代码放在catch 方法上。例如,.catch(e=&gt;{this.results = []; return Observable.empty()})
    • 五分钟前我做了同样的事情,它有效。谢啦! :)
    猜你喜欢
    • 2020-10-24
    • 1970-01-01
    • 2020-05-05
    • 1970-01-01
    • 2019-05-17
    • 2017-10-31
    • 1970-01-01
    • 2022-11-17
    • 2016-05-24
    相关资源
    最近更新 更多