服务仅适用于最新添加的动态创建组件

时间:2018-02-06 12:58:25

标签: angular rxjs multicast

我正在建立一个像Angular中的黄金布局的面板对接系统。我使用动态创建的组件将面板添加到页面中,如下所示:

@ViewChild('dynamicInsert', {read: ViewContainerRef }) dynamicInsert: ViewContainerRef;

/**
* This is the onChanges for the dock component
*/
ngOnChanges() {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.panelType);
    this.dynamicInsert.clear();
    this.panelRef = this.dynamicInsert.createComponent(componentFactory);
    this.panelRef.location.nativeElement.setAttribute('dock-tree-id', this.dockTreeId);
    this.panelRef.location.nativeElement.setAttribute('movable', this.movable);

    this.initializePanel(this.panelRef.instance);
}

dockTree是一个对象,用于保存当前打开的不同面板。这样我就能够非常轻松地将当前布局保存到本地存储。

由于目前我的网页上有多个“停靠点”'像这样:

<div #dock
     class="dock">
  <ng-template #dynamicInsert></ng-template>
</div>

要在这些面板之间进行通信,我正在使用服务。例如,我创建了clickService。一个面板有一个调用click()的按钮,另一个面板调用了getClicks():

@Injectable()
export class ClickService {

  private clicks = 0;
  private observer;

  public getClicks(): Observable<number> {
    return new Observable<number>((observer: Observer<number>) => {
      this.observer = observer;
      observer.next(this.clicks);
    });
  }

  public click() {
    this.clicks++;
    this.observer.next(this.clicks);
  }
}

现在当我点击按钮时,订阅我服务的其他面板应全部更新,但只有最后添加的面板更新:

enter image description here

当我动态添加一个新面板,添加一个新元素并附加面板时,新面板将被订阅,但前一个面板将会中断。将面板拖放到新位置(触发ngOnChanges)时,面板将具有正确的值,但只有最后一个面板将侦听单击。

为什么会这样?

1 个答案:

答案 0 :(得分:1)

问题在于,无论何时调用getClicks,都会使用最新的观察者替换对上一次点击观察者的引用。所以基本上你最多只有一(1)个观察者,与创建的面板数量无关。

private observer;

  public getClicks(): Observable<number> {
    return new Observable<number>((observer: Observer<number>) => {
      this.observer = observer; // replaces the previous observer with the newest
      observer.next(this.clicks); // pushes the current counter to the newest observer
    });

   public click() {
     this.clicks++;
     this.observer.next(this.clicks); // only the latest observer gets the new state
   }
  }

我不知道为什么你选择创建一个observable来组播来自独特来源的点击次数,但这可以通过使用主题来简化:

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class ClickService {
  private readonly _clicks$ = new BehaviorSubject<number>(0);

  readonly clicks$: Observable<number> = this._clicks$.asObservable();

  public click() {
    this._clicks$.next(this._clicks$.value + 1);
    // some would argue that using a sync. value access in a subject is bs
  }
}

现在您应该订阅clicks$流来多播点击次数。