簡體   English   中英

使用BehaviorSubject在同級組件之間共享數據

[英]Using BehaviorSubject to share data between sibling components

我仍在學習Angular,並嘗試查看BehaviorSubject工作原理,但被困在何處。 這是我要做的事:

創建一個名為HeroDetailComponent的搜索框組件,在其中輸入一些文本,並根據此文本搜索英雄列表,並使用另一個HeroesComponent組件將其顯示給用戶。 現在,應該在BehaviorSubject幫助下使用服務組件完成此通信。

這是我的主要組成部分:

app.component.html

<app-hero-detail></app-hero-detail>
<app-heroes></app-heroes>

這是我的hero-detail.component.html,我將其用作搜索框:

  <div>
    <label>name:
      <input [(ngModel)]="hero.name" placeholder="name"/>
    </label>
  </div>

和相應的hero-detail.component.ts

import { Component, OnInit, Input } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

這是我的heroes.component.html ,在這里顯示搜索結果:

<h2>My Heroes</h2>

<ul class="heroes">
  <li *ngFor="let hero of heroes"
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

及其heroes.component.ts

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HEROES } from '../mock-heroes';
import { HeroService } from '../hero.service';
@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})

export class HeroesComponent implements OnInit {

  heroes = HEROES;

  constructor(private heroService: HeroService) { }

    getHeroes(): void {
      // Logic to access heroes list matching search text and display to user
    }

  ngOnInit() {
    this.getHeroes();
  }
}

這是我的服務組件:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable({
  providedIn: 'root'
})
export class HeroService {

    private searchSource = new BehaviorSubject<string>("");
    searchText = this.searchSource.asObservable();

    constructor() { }

    searchByName(name: string) {
        this.searchSource.next(name);
    }

}

這是我的英雄榜模擬數據:

import { Hero } from './hero';

export const HEROES: Hero[] = [
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

您能幫我實現這個問題嗎?

更新:

我按照trichetriche答案中給出的步驟進行操作,但出現以下錯誤:

ERROR in src/app/hero-detail/hero-detail.component.ts(17,16): error TS2339: Property 'formValue$' does not exist on type 'HeroService'.
src/app/hero-detail/hero-detail.component.ts(17,61): error TS2304: Cannot find name 'startWith'.
src/app/heroes/heroes.component.ts(17,13): error TS2304: Cannot find name 'combineLatest'.
src/app/heroes/heroes.component.ts(19,22): error TS2339: Property 'formValue$' does not exist on type 'HeroService'.
src/app/heroes/heroes.component.ts(21,5): error TS2552: Cannot find name 'map'. Did you mean 'Map'?

如何解決這些錯誤?

更新:上面的錯誤現在已解決。 現在我開始面對可觀察的問題:

Observable.js:54 TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    at subscribeTo (subscribeTo.js:41)
    at subscribeToResult (subscribeToResult.js:11)
    at CombineLatestSubscriber.push../node_modules/rxjs/_esm5/internal/observable/combineLatest.js.CombineLatestSubscriber._complete (combineLatest.js:62)
    at CombineLatestSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.complete (Subscriber.js:66)
    at Observable._subscribe (subscribeToArray.js:8)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:43)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:29)
    at CombineLatestOperator.push../node_modules/rxjs/_esm5/internal/observable/combineLatest.js.CombineLatestOperator.call (combineLatest.js:32)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:24)
    at MapOperator.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapOperator.call (map.js:18)

您能幫我解決這個問題嗎?

主題和行為主題是代理:它們既充當可觀察者,又充當觀察者。

您可以在您可以使subject.next subject.next(value)時使代理的觀察者做出反應。next subject.next(value) :主題與行為主題之間的區別在於,主題的觀察者將收到代理的當前值(而主題將僅獲取下next的值)。

所以基本上

BehaviorSubject === Subject.pipe(startWith(someValue))

現在,您實際上不需要行為主體即可完成您想要的事情。 您可以使用一種更簡潔的方法,使用反應形式及其valueChanges屬性。

在您的表單中,使用以下命令:

  <div>
    <label>name:
      <input [formControl]="heroName" placeholder="name"/>
    </label>
  </div>
export class HeroDetailComponent implements OnInit {
  heroName = new FormControl('');
  constructor(
    private service: HeroService
  ) {
    this.service.formValue$ = this.heroName.valueChanges.pipe(startWith(''));
  }
}

您將創建一個表單控件,然后將服務注入到組件中,最后,您將使用該表單控件的valueChanges觀察值對同級中的英雄進行排序。

在服務中,只需添加一個formValue$: Observable<string>即可聲明變量。 xx$只是可觀察對象的命名約定,以便快速發現它們)。

您需要startWith運算符來觸發控件上的第一個值更改(否則,除非您鍵入內容,否則該值不會更改)

最后,在同級中:

export class HeroesComponent implements OnInit {

  private _heroesList$ = new BehaviorSubject(HEROES);

  heroes$;

  constructor(private heroService: HeroService) { }

    getHeroes(): void {
      this.heroes$ = combineLatest(
        this._heroesList$,
        this.heroService.formValue$
      ).pipe(
        map(([list, name]) => list.filter(hero => hero.name.includes(name)))
      );
    }

  ngOnInit() {
    this.getHeroes();
  }
}
<h2>My Heroes</h2>

<ul class="heroes">
  <li *ngFor="let hero of heroes$ | async"
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

這樣,您就可以創建一個由表單值和列表組成的新流,並映射結果以返回過濾后的英雄列表。 您可以使用async管道讓angular處理訂閱,這是一個好習慣,可以防止您忘記取消訂閱。

getHeroes(): void {

  this.heroService.searchText
   .pipe(
     map((name) => HEROES.filter((hero) => hero.name.indexOf(name) !== -1))
   )
   .subscribe((results) => this.heroes = results);
}

然后像這樣循環:

<ul class="heroes">
  <li *ngFor="let hero of heroes"
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM