我有一个简单的应用程序,目的是获取某个位置的当前天气。该位置是默认位置,但是其中一个组件具有按钮,这些按钮应该更改位置,调用API,然后重新显示数据。
所以我有两个部分:位置和WeatherDisplay。我还有一个服务可以完成繁重的工作(基本上是调用API)。
我的问题是,当用户单击新位置时,WeatherDisplay不会更改。我是Angular的初学者,所以让我知道是否在此“演示文稿”中遗漏了一些内容。
我尝试了许多不同的方法,并且我想将其范围缩小到API服务中的某种方法。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { MessageService } from './message.service';
import { BehaviorSubject } from 'rxjs';
import { WeatherStruct } from './weather';
const API_URL = 'http://api.openweathermap.org/data/2.5/weather';
// my key for the OpenWeatherAPI
const API_KEY = '3f25...'; // deleted most of what my key is just 'cause
// default location
const LOCATION_ID = '4480285'; // Morrisville, NC
// get the value from the message
@Injectable({
providedIn: 'root'
})
export class APIService {
private locationSource: BehaviorSubject<any> = new BehaviorSubject(null);
currentLocation = this.locationSource.asObservable();
constructor(
private httpClient: HttpClient,
private msgService: MessageService
) {}
getWeather(loc_id = '4480285'){
// this.msgService.add('api.service.ts '+loc_id);
console.log('api.service getWeather('+loc_id+')');
const api_string = `${API_URL}?id=${loc_id}&APPID=${API_KEY}&units=imperial`;
console.log(api_string);
return this.httpClient.get(api_string);
}
changeLocation(locid: string) {
console.log('api.service changeLocation('+locid+')');
this.locationSource.next(locid);
// need to tell weather-display to re-fetch the data
this.getWeather(locid);
}
}
在位置组件模板中,我有:
<button (click)="newLocation('5391811')">San Diego, CA</button>
天气显示组件:
import { Component, OnInit } from '@angular/core';
import { MessageService } from '../message.service';
import { WeatherStruct } from '../weather';
import { APIService } from '../api.service';
@Component({
selector: 'app-weather-display',
templateUrl: './weather-display.component.html',
providers: [APIService],
styleUrls: ['./weather-display.component.css']
})
export class WeatherDisplayComponent implements OnInit {
weather: WeatherStruct;
private today: number = Date.now();
loc_id: string;
constructor(
private apiService: APIService,
private msgService: MessageService
) {}
ngOnInit() {
this.apiService.currentLocation
.subscribe(location => this.loc_id = location);
this.fetchWeather();
console.log('CCC');
}
fetchWeather(loc_id = '4480285') {
console.log('weather-display.component showWeather(' + loc_id + ')');
this.apiService.getWeather(loc_id).subscribe((data: WeatherStruct) => {
this.weather = data;
this.weather['today'] = this.today;
});
}
}
,并在location.component.ts中:
export class LocationComponent implements OnInit {
location: string;
@Output() talk: EventEmitter<string> = new EventEmitter<string>();
constructor(private apiService: APIService,
private msgService: MessageService) {}
ngOnInit() {
this.apiService.currentLocation.subscribe(
location => (this.location = location)
);
}
newLocation(newLoc: string) {
console.log('location.component newLocation('+newLoc+')');
// use an event emiitter
this.talk.emit(newLoc);
// call a function in the service
this.apiService.changeLocation(newLoc);
}
}
最后是app.component.ts
export class AppComponent implements OnInit {
location: string;
constructor(private apiService: APIService) {}
title = 'The Weather';
ngOnInit() {
this.apiService.currentLocation.subscribe(
location => (this.location = location)
);
}
goGetWeather(newLoc){
console.log("app.component.goGetWeather("+newLoc+")");
}
}
当我执行我的应用程序并尝试单击一个按钮时,我看到代码像我期望的那样执行:
location.component newLocation()被调用,该调用 app.component.goGetWeather [告诉我事件发射器正在运行];和 api.service changeLocation ,导致 api.service getWeather 会生成正确格式的API字符串以供调用
http://api.openweathermap.org/data/2.5/weather?id=2643743&APPID=3f25...&units=imperial
但DisplayWeather组件中没有任何变化。
我知道这很简单,但是我无法直言不对。
答案 0 :(得分:0)
这可以通过使用共享服务来实现。请参阅有关如何实现共享服务的链接:http://www.angulartutorial.net/2017/09/angular-share-data-between-components.html
这是代码的样子:
Service.ts
b.b()
在您点击城市变化的按钮的第一个组件中,调用service.setCityChange()
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class SharedService {
// Subject (emitter) for User Name Change
CityNameChange: Subject<string> = new Subject<string>();
// SetUserChange() - This method sets the local variable and emits the change
SetCityChange(param: string) {
this.CityNameChange.next(param);
}
}
在第二个组件中,在ngOnInit中,订阅城市更改事件并获取基于新城市的天气数据:
this._sharedService.SetCItyChange(newCityName);
答案 1 :(得分:0)
如果我正确解决了您的问题,则数据无法正常流动。您可以通过使用更多的RxJS来解决此问题。看看我将如何实现它。
// Dont use any inside your source code, use an type alias while you are working dirty instead.
type Location = any;
type Weather = any;
// The name is not really correct anymore, it is more a WeatherLocService..
@Injectable()
export class APIService {
defaultLocation = {
// .. or handle the cases where currentLocation emits null anyhow.
};
// Holds the current location
private currentLocation$ = new BehaviorSubject<Location | null>(null);
// Holds the weather at the current location
weatherAtLocation$: Observable<Weather>;
constructor(private httpClient: HttpClient) {
// Whenever location changes, call getWeather with the new location and return the result
this.weatherAtLocation$ = this.currentLocation$.pipe(
mergeMap(location => this.getWeather(location))
)
}
getWeather(location: Location = this.defaultLocation): Observable<Weather> {
return this.httpClient.get("https://www.example.com");
}
updateLocation(location: Location) {
this.currentLocation$.next(location);
}
}
https://stackblitz.com/edit/angular-umqxpv?file=src%2Fapp%2Fapi.service.ts