【问题标题】:Share dynamically created observable between components在组件之间共享动态创建的 observable
【发布时间】:2019-07-21 18:55:50
【问题描述】:

我有两个兄弟组件,它们需要访问在可观察对象中检索到的数据,该可观察对象是基于用户输入可观察对象在服务中动态创建的。我很难理解如何让search-list 组件收听search 组件创建的可观察对象。我应该将服务创建的最后一个搜索 observable 存储为搜索服务中的另一个 observable,我应该将搜索 observable 存储在 search 组件中并通过 ref 访问,还是应该在观察者在 @ 中完成后发出数据987654324@组件?

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}`);
    });
    */
  } 
}

【问题讨论】:

    标签: angular rxjs observable


    【解决方案1】:

    只需使用主题来共享状态并将“加载状态”操作与“接收状态”操作分开。

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

    搜索列表.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}`);
        });
      } 
    }
    

    【讨论】:

    • 我应该调用 this.loading.next(true) / this.loading.next(false) 来更新吧?
    【解决方案2】:

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

    另一种选择是将这个 observable 添加到服务中,并将服务注入到两个组件中。这也将起作用。

    这是两种方法的stackblitz example

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-31
      • 2019-08-05
      • 1970-01-01
      • 1970-01-01
      • 2017-05-06
      • 2019-02-18
      • 2016-01-25
      • 2018-10-09
      相关资源
      最近更新 更多