行为主题仅显示初始值/重放主题不显示更新的值

时间:2020-04-07 05:41:00

标签: angular rxjs behaviorsubject subject-observer

背景:

我有一个基于开放图层的地图服务。地图组件具有其自己的服务。

单击图标会生成一个弹出窗口。在此弹出窗口上是一个按钮,单击该按钮可从弹出窗口上显示的对象中获取一些数据,然后导航到其他组件。

我正在尝试将此数据发布/添加到行为主题,然后在新组件中对其进行订阅。单击该图标时,数据将添加到行为主题。弹出组件具有其自己的服务。

在目标组件中,我试图使用异步管道订阅模板中的弹出服务行为主题。

问题:

行为主体上的可观察对象仅返回初始值。行为主题的下一个功能似乎并未向其添加新数据。它总是赋予新的价值。

使用重播主题时,没有任何显示。下一步功能似乎根本没有任何作用。

代码:

弹出式服务

_analysisBehaviourSubject: BehaviorSubject<any> = new BehaviorSubject();


// other code

addElement(element: any) {
    console.log('adding new element to behaviour subject', element);
    this._analysisBehaviourSubject.next(element);
}

getElement$(): Observable<any> {
    return this._analysisBehaviourSubject.asObservable();
}

地图服务

getAnalysisBehaviourSubject(): Observable<any> {
    return this.clusPopupService.getElement$();
}

目的地服务

getAnalysisBehaviourSubject(): Observable<any> {
    return this.mapService.getAnalysisBehaviourSubject();
}

然后在目标组件中仅存在一个异步管道。

我已经尝试过的方法:

  1. 直接从弹出服务中导入行为主题,而无需在我的项目结构中移动它。

  2. 使用行为主题代替示例代码中所示的重放主题。

  3. 将所有三个服务添加到app.module.ts中的providers数组。行为主体仍然发出原始值,而重放主体则什么也没有发出。

更新弹出式服务

import { DataPreparationService } from './data-preparation.service';
import { GeneralService } from '../../general.service';
import { Injectable } from '@angular/core';
import OlMap from 'ol/Map';
import OlView from 'ol/View';
import { fromLonLat } from 'ol/proj';
import Overlay from 'ol/Overlay';
import Point from 'ol/geom/Point.js';
import { SourceDataObject } from '../../Models/sourceDataObj';
import { Select } from 'ol/interaction';
import { CookieService } from 'ngx-cookie-service';
import { StoreService } from 'src/app/store.service';

@Injectable({
  providedIn: 'root'
})
export class ClusterPopupService {
  // analysis variables
  deltaEX = 1;
  deltaEy = 3;
  overlayCoords: object = {};
  sourceDataObj: SourceDataObject = { element: '', coordinates: null };
  detectedPoints: Point[] = [];

  // pop up variables
  foundIcon: SourceDataObject;
  newPoint: Point;
  generalSelect: Select;
  num = 0;
  // analysis page Behaviour Subjects
  constructor(
    private genService: GeneralService,
    private dataPrepService: DataPreparationService,
    private cookies: CookieService,
    private store: StoreService
  ) {}

  // behaviour subject m1ethods

  //cluster methods
  filterPoints(newPoint: Point) {
    const newPointCoords: number[] = newPoint.getCoordinates();

    if (this.detectedPoints.length >= 1) {
      for (let i = 0; i <= this.detectedPoints.length - 1; i++) {
        const savedPointCoords = this.detectedPoints[i].getCoordinates();
        if (
          savedPointCoords[0] === newPointCoords[0] &&
          savedPointCoords[1] === newPointCoords[1]
        ) {
          break;
        } else if (i === this.detectedPoints.length - 1) {
          this.detectedPoints.push(newPoint);
        }
      }
    } else {
      this.detectedPoints.push(newPoint);
    }
  }
  async clearFeatureCache() {
    this.foundIcon = undefined;
    this.generalSelect.getFeatures().clear();
    this.detectedPoints = null;
  }
  pushToCookies(currView: OlView) {
    this.cookies.deleteAll();
    const currCoordinates: number[] = currView.getCenter();
    const longitudeString: string = currCoordinates[0].toString();
    const latitudeString: string = currCoordinates[1].toString();
    const zoomLevelString: string = currView.getZoom().toString();
    this.cookies.set('longitude', longitudeString, 1 / 48);
    this.cookies.set('latitude', latitudeString, 1 / 48);
    this.cookies.set('zoom', zoomLevelString, 1 / 48);
    console.log(
      this.cookies.get('longitude'),
      this.cookies.get('latitude'),
      this.cookies.get('zoom')
    );
  }

  async preparePopup(
    fishCoords: SourceDataObject[],
    munitCoords: SourceDataObject[],
    wrackCoords: SourceDataObject[],
    sedimentCoords: SourceDataObject[],
    generalSelect: Select,
    view: OlView,
    globalMap: OlMap,
    localDoc?: Document
  ) {
    const extent: number[] = view.calculateExtent(globalMap.getSize());
    const container = localDoc.getElementById('popup');
    const content = localDoc.getElementById('popup-content');
    const closer = localDoc.getElementById('popup-closer');
    const analyseButton = localDoc.getElementById('analyseButton');

    const popUpOverlay: Overlay = new Overlay({
      element: container,
      autoPan: true
    });
    this.generalSelect = generalSelect;
    closer.onclick = () => {
      popUpOverlay.setPosition(undefined);
      this.foundIcon = undefined;
      generalSelect.getFeatures().clear();
      this.detectedPoints = null;

      this.newPoint = null;

      closer.blur();
      return false;
    };

    globalMap.addOverlay(popUpOverlay);
    generalSelect.on('select', event => {
      this.newPoint = event.selected[0].getGeometry() as Point;

      this.foundIcon = this.dataPrepService.binSearch(
        wrackCoords,
        this.newPoint.getCoordinates(),
        'wrack Array'
      );

      if (this.foundIcon === undefined) {
        this.foundIcon = this.dataPrepService.binSearch(
          sedimentCoords,
          this.newPoint.getCoordinates(),
          'sediment array'
        );
      }
      if (this.foundIcon === undefined) {
        this.foundIcon = this.dataPrepService.binSearch(
          fishCoords,
          this.newPoint.getCoordinates(),
          'fish array'
        );
      }

      if (this.foundIcon === undefined) {
        this.foundIcon = this.dataPrepService.binSearch(
          munitCoords,
          this.newPoint.getCoordinates(),
          'munition array'
        );
      }
      if (this.foundIcon !== undefined) {
        this.sourceDataObj = this.foundIcon;
        popUpOverlay.setPosition(fromLonLat(this.foundIcon.coordinates));
      } else {
        if (this.sourceDataObj === null) {
          this.sourceDataObj = { element: '', coordinates: null };
          this.sourceDataObj.element = 'not found';
          console.log(this.genService.backEndUri);
        }
        this.sourceDataObj.element = 'not found';
        popUpOverlay.setPosition(this.newPoint.getCoordinates());
      }
      console.log('the icon found is:', this.foundIcon);
      switch (this.sourceDataObj.element) {
        case 'sediment':
          content.innerHTML =
            '<p>You clicked on a <code>' +
            this.sourceDataObj.element +
            '</code> with coordinates <code>' +
            this.sourceDataObj.coordinates +
            '</code>, and  ID <code>' +
            this.sourceDataObj.sampleId +
            '</code>. Analyse this element?</p><p><button onclick="window.location.href=\'' +
            this.genService.localUri +
            '/analyseSediment' +
            '\'"' +
            'id="analyseButton">Analyse</button></p>';
          this.sourceDataObj = null;
          this.pushToCookies(view);
          break;
        case 'fish':
          this.store.addElement(this.sourceDataObj.miscData);

          content.innerHTML =
            '<p>You clicked on a <code>' +
            this.sourceDataObj.element +
            '</code> with coordinates <code>' +
            this.sourceDataObj.coordinates +
            '</code>,  cruise ID <code>' +
            this.sourceDataObj.miscData.cruiseId +
            '</code> and target ID <code>' +
            this.sourceDataObj.miscData.sampleId +
            '</code>. Analyse this element?</p><p><button onclick="window.location.href=\'' +
            this.genService.localUri +
            '/analyseFish' +
            '\'"' +
            ' id="analyseButton">Analyse</button></p>';

          this.sourceDataObj = null;
          this.pushToCookies(view);

          break;
        case 'Munition':
          content.innerHTML =
            '<p>You clicked on a <code>' +
            this.sourceDataObj.element +
            '</code> with coordinates <code>' +
            this.sourceDataObj.coordinates +
            '</code>,  cruise ID <code>' +
            this.sourceDataObj.miscData.cruiseId +
            '</code> and target ID <code>' +
            this.sourceDataObj.miscData.targetId +
            '</code>. Analyse this element?</p><p><button onclick="window.location.href=\'' +
            this.genService.localUri +
            '/analyseMunition' +
            '\'"' +
            'id="analyseButton">Analyse</button></p>';
          this.sourceDataObj = null;
          this.pushToCookies(view);
          break;
        case 'wrack':
          content.innerHTML =
            '<p>You clicked on a <code>' +
            this.sourceDataObj.element +
            '</code> with coordinates <code>' +
            this.sourceDataObj.coordinates +
            '</code>, and  target ID <code>' +
            this.sourceDataObj.miscData.targetId +
            '</code>. Analyse this element?</p><p><button onclick="window.location.href=\'' +
            this.genService.localUri +
            '/analyseWrack' +
            '\'"' +
            ' id="analyseButton">Analyse</button></p>';
          this.sourceDataObj = null;
          this.pushToCookies(view);
          break;
        case 'not found':
          content.innerHTML =
            '<p>You selected more than one Icon. Please Zoom in and select only one for analysis</p>';
          break;
        default:
          content.innerHTML =
            '<p>The map feature wasn"t quite selected. Please close the pop up and retry</p>';
          break;
      }
    });
  }
}

商店服务

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

@Injectable({
  providedIn: 'root'
})
export class StoreService {
  _analysisBehaviourSubject: BehaviorSubject<any> = new BehaviorSubject();
  analysis$: Observable<any> = this._analysisBehaviourSubject.asObservable();
  constructor() {
    console.log('I AM THE STORE');
  }

  addElement(element: any) {
    console.log('adding new element to behaviour subject', element);
    this._analysisBehaviourSubject.next(element);
  }
  getElement$(): Observable<any> {
    return this.analysis$;
  }
}

2 个答案:

答案 0 :(得分:1)

我知道了。主题图案及其阴影效果很好。

在上面的弹出服务中,我通过href导航到组件。我最好的猜测是,这会破坏组件树,并且保存值的服务实例也会被破坏。

尽管我不能证明这一点,但是我确实尝试实现一个重放主题,以便在我从一个组件导航到另一个组件时进行更新,然后在我在项目的新组件中订阅该组件,并且效果很好。因此,我将此固定在href的使用上。

在按下内部html中用于打开图层的按钮之后,需要找到另一种路由到我的组件的方法。

感谢所有抽出时间阅读或回复此问题的人。

答案 1 :(得分:0)

我认为发生的事情是,每次使用asObservable()函数调用getElement $()时,您都会创建一个新的可观察的对象。我觉得the docs对此不是100%清楚。

我建议在类级别而不是方法级别也创建可观察对象。

因此,在您的Popup服务中,您可以执行以下操作:

_analysisBehaviourSubject: ReplaySubject<any> = new ReplaySubject();
_analysis$: Observable<any> = this._analysisBehaviourSubject.asObservable();

或者,您可以在主题扩展为“可观察”时直接订阅该主题。