未触发可观察到的next()回调

时间:2019-03-11 07:12:01

标签: javascript angular typescript rxjs ngrx

我正在尝试实现一个可在整个应用程序中重用的全局加载指示器。我有一个具有显示和隐藏功能的可注射服务:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class SpinnerOverlayService {
    private loaderSubject = new Subject<any>();


    public loaderState = this.loaderSubject.asObservable();

    constructor() { }

    /**
     * Show the spinner
     */
    show(): void {
        this.loaderSubject.next(<any>{ show: true });
    }

    /**
     * Hide the spinner
     */
    hide(): void {
        this.loaderSubject.next(<any>{ show: false });
    }
}

这是微调器叠加层组件的代码。我将排除有关HTML和CSS实现的详细信息,因为它们在这里并不重要。

import { Component, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { SpinnerOverlayService } from '../spinner-overlay.service';

@Component({
  selector: 'spinner-overlay',
  templateUrl: './spinner-overlay.component.html',
  styleUrls: ['./spinner-overlay.component.scss']
})
export class SpinnerOverlayComponent implements OnInit {

  show = false;

  private _subscription: Subscription;

  constructor(private spinnerOverlayService: SpinnerOverlayService) { }

  ngOnInit(): void {
    this._subscription = this.spinnerOverlayService.loaderState.subscribe((state) => {
        console.log("Subscription triggered.");
        this.show = state.show;
      });
  }

  ngOnDestroy(): void {
    this._subscription.unsubscribe();
  }
}

问题:在覆盖组件的代码中,我正在订阅服务的可观察loaderState。但是,当我调用触发可观察对象的next()的show()函数时,不会触发订阅回调。

这就是我在app.component.ts中调用show()函数的方式:

ngOnInit() {
               this.spinnerOverlayService.show();
}

我可能会缺少什么?回调未触发似乎很奇怪。

以下是Stackblitz中的一个示例:https://stackblitz.com/edit/angular-7-registration-login-example-2qus3f?file=app%2Fspinner-overlay%2Fspinner-overlay.component.ts

2 个答案:

答案 0 :(得分:3)

问题是您在初始化this.spinnerOverlayService.show();之前调用了spinner-overlaySubject不保留先前发出的值,因此,除非有新值,否则后期订户将不会获得任何值。

您可以做的一件事是将Subject更改为BehaviorSubject,这将向新订阅者发出最后一个值。

或者,您可以在this.spinnerOverlayService.show();内致电ngAfterViewInit。 这样,您将知道spinner-overlay将被初始化并订阅spinnerOverlayService.loaderState

ngAfterViewInit() {
  this.spinnerOverlayService.show();
}

Check it out

答案 1 :(得分:2)

除了上述答案外,您还可以在spinnerOverlayService服务中有一个状态来检查显示隐藏,如果有新值准备好,还可以有一个主题要订阅:

 ngOnInit(): void {
    if(this.spinnerOverlayService.state.show){
      console.log('Subscription triggeredd.');
    };
    this._subscription = this.spinnerOverlayService.loaderState.subscribe((state) => {
        console.log("Subscription triggered.");
        this.show = state.show;
      });
  }

和您的ngOnInit中:

private loaderSubject = new ReplaySubject(1); // to cache last value

或者您可以使用:

const Promise = require('promise')

function getWeather(encodedAddress, units, language) {
    return new Promise((resolve, reject) => {
        let geoKey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX';
        let geocodeURL = `http://www.mapquestapi.com/geocoding/v1/address?key=${geoKey}&location=${encodedAddress}`;

    axios.get(geocodeURL).then(({ data }) => {
        if (((data.results[0].locations[0].geocodeQualityCode.substring(2)).match(/X/g) || []).length > 1) {
            throw new Error('Unable to find that address')
        }
        const locationInfo = data.results[0].locations[0];
        const lat = locationInfo.latLng.lat;
        const lng = locationInfo.latLng.lng;

        console.log('Here\'s the weather for: ', locationInfo.street, locationInfo.adminArea5,
            locationInfo.adminArea4, locationInfo.adminArea1,
            locationInfo.postalCode);

        const weatherKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxx';

        units = units ? `units=${units}` : 'auto';
        language = language ? `lang=${language}` : 'lang=en';

        const weatherURL = `https://api.darksky.net/forecast/${weatherKey}/${lat},${lng}?${units}&${language}`;
        axios.get(weatherURL).then(resolve).catch(reject);

    }).then(({ data }) => {
        const tempInfo = data.currently;
        const temp = tempInfo.temperature;
        const apparentTemp = tempInfo.apparentTemperature;
        const summary = tempInfo.summary;

        console.log(`It's currently ${temp} degrees and feels like ${apparentTemp} degrees. \nThe local summary is: ${summary}.`);

        resolve(data.currently);

    }).catch(error => {
        if (error.code === 'ENOTFOUND') {
            reject(new Error('Could not connect to MapRequest server'));
        } else {
            reject(Error(error.message));
        }
    });
});
};

Series.isna