使用Observables

时间:2016-12-30 03:14:25

标签: javascript angular rxjs

我使用Observables来携带从父组件到子组件的值。

这是我的顶级应用程序组件:

import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { ViewModel } from './ViewModel.data';
import { ViewComponent } from './ViewComponent.component';

@Component({
    selector: ...,
    directives: [
        ROUTER_DIRECTIVES,
        ViewComponent
    ],
    precompile: [],
    styles: [],
    template: `
            <div>
            <ul class="nav nav-tabs">
              <li *ngFor="let v of views"><a (click)="setView(v)">{{ v.name }}</a></li>
            </ul>
              <viewcomponent
                *ngFor="let v of views"
                [viewName]="v.name"
                [activeViewObservable]="activeViewObservable"></viewcomponent>
            </div>
    `
})
export class AppComponent{
    views:ViewModel[];
    activeViewObservable:Observable<ViewModel>;
    viewObserver:Observer<ViewModel>;
    activeView:ViewModel;

    constructor() {
        this.views = [{name: 'one'}, {name: 'two'}, {name: 'three'}, {name: 'four'}];
        this.activeViewObservable = new Observable<ViewModel>(observer => this.viewObserver = observer);
    }

    public setView(view:ViewModel):void {
        this.viewObserver.next(view); // load values here
      }
}

我在这里使用名为viewcomponent的组件:

@Component({
    selector: 'viewcomponent',
    directives: [
        ROUTER_DIRECTIVES
    ],
    template: `
        <div class="tab-pane" [ngClass]="{ 'active': isActive() }">
            ...
        </div>
      `
})
export class ViewComponent {
    // these values are always the last view. why???
    @Input() viewName:string;
    @Input() activeViewObservable:Observable<TabViewModel>;

    private activeView:ViewModel;

    constructor() {}

    ngOnInit() {
        this.activeViewObservable.subscribe( //listen to values loaded with the viewObserver
            activeView => {this.activeView = activeView;},
            error => console.error(error));
    }

    public isActive():boolean {
        let bool:boolean = false;
        if (this.activeView) {
            console.log(this.viewName); // <---- this value is always the last view, 'four'
            bool = this.activeView.name == this.viewName;
        }
        console.log(bool);
        return bool;
    }
}

我正在使用的数据模型在这里:

export interface ViewModel {
    name: string;
}

我正在尝试使用AppComponent中的值加载观察者,然后在子项中订阅它们。但是,observable发出的值始终是最后一个元素。

我想调用父项中的setView方法,然后将一个类应用于该特定的子视图。

1 个答案:

答案 0 :(得分:1)

可能的解决方案如果您要在Subject的实例化之外的.next()上调用Observer,请使用ObservableSubject表现为两者。您可以将活动传递给它的地方单独订阅。 Plunker Example

为什么您的代码不起作用?

使用rxjs的代码可以这样写:

let viewObserver;
const myObservable = new Observable(observer => {
  viewObserver = observer;
});

myObservable.subscribe(
  activeView => {
    console.log(1, activeView);
  },
  error => console.error(error));

myObservable.subscribe(
  activeView => {
    console.log(2, activeView);
  },
  error => console.error(error));

viewObserver.next({ name: 'one' });

https://jsfiddle.net/t5z9jyf0/

预期产量是多少?

2, { name: 'one' }

<强>为什么吗

让我们打开rxjs文档

关键点有:

  

使用Observer调用observable.subscribe时,该函数   订阅Observable.create(函数subscribe(observer){...})是   为那个给定的Observer运行。每次调用observable.subscribe   为给定的观察者触发它自己的独立设置。

let viewObserver;
var myObservable = new Observable<ViewModel>(function subscribe(observer) {
  console.log(observer, observer.destination._next);
  viewObserver = observer;
});

myObservable.subscribe( // this triggers subscribe function above
  activeView => {
    console.log(1, activeView);
  },
  error => console.error(error));


myObservable.subscribe( // this also triggers subscribe function above
  activeView => {
    console.log(2, activeView);
  },
  error => console.error(error));


viewObserver.next({ name: 'one' }); // notify subscriptions

https://jsfiddle.net/t5z9jyf0/1/

因此在

之后代码不起作用
myObservable.subscribe(
  activeView => {
    console.log(2, activeView);
  },
  error => console.error(error));

方法已执行,viewObserver将被覆盖,Subscriber对象来自activeView => { console.log(2, activeView); },因此viewObserver.next会给我们

console.log(2, { name: 'one' });

这就是为什么只执行最后一次订阅