代码之家  ›  专栏  ›  技术社区  ›  learner

使用BehaviorSubject在同级组件之间共享数据

  •  1
  • learner  · 技术社区  · 7 年前

    BehaviorSubject 工作正常,但却被困在哪里开始。以下是我想做的:

    HeroDetailComponent 在这里,我输入一些文本,并根据这些文本搜索英雄列表,并使用另一个组件向用户显示他们 HeroesComponent . 现在,应该使用服务组件在的帮助下完成此通信

    以下是我的主要内容:

    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>
    

    以及相应的

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

    这是我的 ,我在这里显示搜索结果:

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

    及其 heromes.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)
    

    你能帮我解决这个问题吗。

    2 回复  |  直到 5 年前
        1
  •  1
  •   user4676340 user4676340    7 年前

    你可以让代理的观察者在你不能的时候做出反应 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(''));
      }
    }
    

    您将创建一个表单控件,然后将服务注入到组件中,最后使用 价值变化 可以观察到表单控件对兄弟姐妹中的英雄进行排序。

    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

        2
  •  -1
  •   Chrillewoodz    7 年前
    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>
    
    推荐文章