this.myService.myEvent.toRx().subscribe() called b

2019-09-02 17:38发布

问题:

I'm playing with angular2 alpha 40 with ng2-play starter from pawel. Examples are in typescript.

I have a service MovieList like this:

export class Movie {
  selected: boolean = false
  constructor(public name:string, public year:number, public score:number) {}
}

export class MovieListService {
  list: Array<Movie>
  selectMovie = new EventEmitter();

  constructor() {
    this.list = [new Movie('Star Wars', 1977, 4.4)];
  }

  add(m:Movie) {
    this.list.push(m);
  }

  remove(m:Movie) {
    for(var i = this.list.length - 1; i >= 0; i--) {
        if(this.list[i] === m) {
           if(m.selected) this.selectMovie.next();
           this.list.splice(i, 1);
        }
    }
  }

  select(m:Movie) {
    this.list.map((m) => m.selected = false);
    m.selected = true;
    this.selectMovie.next(m);
  }

}

I have a component showing the movies list and make possible to select one by clicking on it, which call select() in the service above.

And I have another component (on the same level, I don't want to use (selectmovie)="select($event)") which subscribe to the movie selection event like this:

@Component({
  selector: 'movie-edit',
})
@View({
    directives: [NgIf],
    template: `
      <div class="bloc">
          <p *ng-if="currentMovie == null">No movie selected</p>
          <p *ng-if="currentMovie != null">Movie edition in progress !</p>
      </div>
    `
})

export class MovieEditComponent {
  currentMovie:Movie

  constructor(public movieList: MovieListService) {
      this.movieList.selectMovie.toRx().subscribe(this.movieChanged);

      setTimeout(() => { this.movieChanged('foo'); }, 4000);
  }

  movieChanged(f:Movie = null) {
      this.currentMovie = f;

      console.log(this.currentMovie);      
  }
}

The event is subscribed using .toRx().subscribe() on the eventEmitter. movieChanged() is called but nothing happen in the template.. I tried using a timeout() calling the same function and changes are refleted in the template.

回答1:

The problem seems to be the fact that subscribe expects an Observer or three functions that work as an observer while you are passing a normal function. So in your code I just changed movieChanged to be an Observer instead of a callback function.

  movieChanged: Observer = Observer.create(
    (f) => { this.currentMovie = f; }, // onNext
    (err) => {},                       // onError
    () => {}                           // onCompleted
  );

See this plnkr for an example. It would have been nice to see a minimal working example of your requirement so my solution would be closer to what you are looking for. But if I understood correctly this should work for you. Instead of a select I just used a button to trigger the change.

Update

You can avoid creating the Òbserver just by passing a function to the subscriber method (clearly there's a difference between passing directly a function and using a class method, don't know really why is different)

this.movieList.selectMovie.toRx().subscribe((m: Movie = null) => {
    this.currentMovie = m;
});

Note

EventEmitter is being refactored, so in future releases next will be renamed to emit.

Note 2

Angular2 moved to @reactivex/rxjs but in the plnkr I'm not able to use directly those libs (didn't find any cdn). But you can try in your own project using these libs.

I hope it helps.



回答2:

The movieChanged function expects the movie object and not the String. Try changing below code

setTimeout(() => { this.movieChanged('foo'); }, 4000);

to

setTimeout(() => { this.movieChanged(new Movie('Troy', 2000 , 8)); }, 4000);