我正在尝试实现一个可在整个应用程序中重用的全局加载指示器。我有一个具有显示和隐藏功能的可注射服务:
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
答案 0 :(得分:3)
问题是您在初始化this.spinnerOverlayService.show();
之前调用了spinner-overlay
。 Subject
不保留先前发出的值,因此,除非有新值,否则后期订户将不会获得任何值。
您可以做的一件事是将Subject
更改为BehaviorSubject
,这将向新订阅者发出最后一个值。
或者,您可以在this.spinnerOverlayService.show();
内致电ngAfterViewInit
。
这样,您将知道spinner-overlay
将被初始化并订阅spinnerOverlayService.loaderState
ngAfterViewInit() {
this.spinnerOverlayService.show();
}
答案 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));
}
});
});
};