Обмен динамически созданными наблюдаемыми между компонентами - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть два родственных компонента, которым требуется доступ к данным, полученным в наблюдаемой, которая динамически создается в службе на основе наблюдаемой пользовательской информации.Я изо всех сил пытаюсь понять, как я могу заставить компонент 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 голосов
/ 28 февраля 2019

просто используйте тему, чтобы поделиться состоянием и отделить действие «загрузка состояния» от действия «получение состояния».

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.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}`);
    });
  } 
}
0 голосов
/ 28 февраля 2019

Один из вариантов - переместить searchTerm$ Наблюдаемый на один уровень вверх к компоненту, который охватывает их оба.И затем вы можете передать его в оба из них как @Input, и он будет прослушивать обновления внутри них.И если вам нужно обновить его, вы также можете передать функцию @Output, чтобы обновить значение наблюдаемого в родительском компоненте.

Другой вариант - добавить это наблюдаемое в службу и внедрить службу в оба компонента.Это также будет работать.

Вот пример stackblitz обоих методов.

...