在组件之间共享动态创建的可观察对象

时间:2019-02-27 23:01:40

标签: angular rxjs observable

我有两个同级组件,它们需要访问在可观察对象中检索的数据,该可观察对象是根据可观察的用户输入在服务中动态创建的。我正在努力了解如何获取search-list组件来监听search组件创建的可观察对象。我应该将服务创建的最后一个可观察到的搜索存储为搜索服务中的另一个可观察到的存储,还是应该将可观察到的搜索存储在search组件中并通过引用进行访问,或者应该在观察者完成操作后发出数据? search组件?

search.service.ts

export interface SearchApi {
 data: string[]
}

export class SearchService {
  loading: EventEmitter<boolean> = new EventEmitter();

  constructor(private httpClient: HttpClient) {

  }

  search(terms: Observable<string>){
     return terms.pipe(debounceTime(400))
     .pipe(distinctUntilChanged())
     .pipe(switchMap(term => {
        this.loading.emit(true);
        return this.searchEntries(term);
     }))
     .pipe((data) => {
        this.loading.emit(false);
        return data;
     });
  }

  searchEntries(term){
    return this.httpClient.post<SearchApi>(this.baseUrl,term);
  }
}

search.component.ts

import { Subject, Observable } from 'rxjs';

export class SearchComponent implements OnInit {

  searchTerm$ = new Subject<string>();

  constructor(private searchService: SearchService) {
    searchService.loading.subscribe(isLoading => {
      console.log(`Is loading: ${isLoading}`);
    });

    searchService.search(this.searchTerm$).subscribe(results => {
      console.log(`Search results ${results}`);
    });
  } 
}

search-list.component.ts

export class SearchListComponent implements OnInit {

  constructor(private searchService: SearchService) {
    searchService.loading.subscribe(isLoading => {
      console.log(`Is loading: ${isLoading}`);
    });

    /* Not sure how I would subscribe to observable that search.service.ts created */
    /*
    searchService.search().subscribe(results => {
      console.log(`Search results ${results}`);
    });
    */
  } 
}

2 个答案:

答案 0 :(得分:2)

仅使用主题即可共享状态并将“加载状态”操作与“接收状态”操作区分开。

export class SearchService {
  private loading: Subject<boolean> = new Subject(); // use subjects, keep them private
  loading$: Observable<boolean> = this.loading.asObservable(); // public observable


  private searchResults = new BehaviorSubject(null);  // BehaviorSubjects solve timing problems
  searchResults$ = this.searchResults.asObservable(); 

  constructor(private httpClient: HttpClient) {

  }

  search(terms: Observable<string>){
     return terms.pipe(
         debounceTime(400), // cleaner syntax / less pipes
         distinctUntilChanged(),
         tap(v => this.loading.next(true)), // subjectsuse next, use tap for side effects
         switchMap(term => this.searchEntries(term)),
         tap(v => this.loading.next(false)) // use tap for side effects
     ).subscribe(this.searchResults); // send it to the subject
  }

  searchEntries(term){
    return this.httpClient.post<SearchApi>(this.baseUrl,term);
  }
}

然后在您的组件中,订阅searchResults $,并在要填充搜索结果时调用search()。

search.component.ts

import { Subject, Observable } from 'rxjs';

export class SearchComponent implements OnInit {

  searchTerm$ = new Subject<string>();

  constructor(private searchService: SearchService) {
    searchService.loading$.subscribe(isLoading => {
      console.log(`Is loading: ${isLoading}`);
    });

    searchService.search(this.searchTerm$); // call the state load action
  } 
}

search-list.component.ts

export class SearchListComponent implements OnInit {

  constructor(private searchService: SearchService) {
    searchService.loading$.subscribe(isLoading => {
      console.log(`Is loading: ${isLoading}`);
    });

    searchService.searchResults$.subscribe(results => { // receive state here
      console.log(`Search results ${results}`);
    });
  } 
}

答案 1 :(得分:1)

其中一种选择是将searchTerm$可观察的层移动到包装了这两个层的组件上。然后,您可以将其作为@Input传递给它们两个,它将监听它们内部的更新。并且,如果需要更新它,还可以传递@Output函数来更新父组件中可观察值的值。

另一个选择是将此可观察项添加到服务中,然后将该服务注入两个组件中。那也可以。

这是两种方法的stackblitz example