如何解决嵌套可观测对象和以角度加载内容的问题
我开始使用天气api创建我的第一个应用程序,在第一个加载视图中,我希望通过订阅可观察对象来发出3个请求,这三个类型均为get,每个类型都取决于以下内容:>
1-获取所有状态的列表 2-获取每个州的部门列表 3-从每个随机状态获得部门的预测
我要面对的问题是,在发出不同的串联请求时,在所有加载完成之前,我不希望在表中加载数据,但这使我非常困难,因为我尝试放置在代码的开始处有一个加载变量,在变量的末尾有一个加载变量,该变量存在于第2点和第3点之间,但不能按预期工作。
我的代码如下:
general.component.ts:
import { Component,OnInit } from '@angular/core';
import { eltiempoDataService } from 'src/app/services/eltiempo-data.service';
import { weatherGeneralModel } from 'src/app/models/weatherGeneral.model';
@Component({
selector: 'app-general',templateUrl: './general.component.html',styleUrls: ['./general.component.css']
})
export class GeneralComponent implements OnInit {
data_mun: weatherGeneralModel[] = [];
loading_data: boolean;
constructor(private eltiempoDataService: eltiempoDataService) {
this.getRandomMunicipio()
console.log('finish2')
}
ngOnInit() {
}
getRandomMunicipio() {
let provs
let prov_random: {}
this.getProvincias().subscribe((data: any[]) => {
this.loading_data = true;
provs = data['provincias']
this.processData(provs)
})
}
processData(provs: any[]){
for (let prop in provs) {
this.getMunicipios(provs[prop]['CODPROV']).subscribe((data_municipios) => {
let object_data_general: weatherGeneralModel = new weatherGeneralModel()
let local_muni: any[] = data_municipios['municipios']
var random = Math.floor(Math.random() * local_muni.length);
let cod_ine_mun = local_muni[random]['CODIGOINE'].toString().substring(0,5);
this.getDataMunicipio(provs[prop]['CODPROV'],cod_ine_mun).subscribe((data_predict) => {
object_data_general.comunidad = provs[prop]['COMUNIDAD_CIUDAD_AUTONOMA']
object_data_general.provincia = provs[prop]['NOMBRE_PROVINCIA']
object_data_general.municipio = data_predict['municipio']['NOMBRE']
object_data_general.pronostico = data_predict['temperaturas']['max'] + '/' + data_predict['temperaturas']['min']
object_data_general.cod_prov = provs[prop]['CODPROV']
this.data_mun.push(object_data_general)
})
})
}
this.loading_data = false;
}
getProvincias() {
return this.eltiempoDataService.getProvincias()
}
getMunicipios(cod_prov: string) {
return this.eltiempoDataService.getMunicipios(cod_prov)
}
getDataMunicipio(cod_prov: string,id_muni: string) {
return this.eltiempoDataService.getDataMunicipio(cod_prov,id_muni)
}
}
eltiempo-dataService.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient,HttpHeaders } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class eltiempoDataService {
constructor(private http: HttpClient) {
console.log('servicio ElTiempo.net listo')
}
getProvincias(){
return this.http.get('https://www.el-tiempo.net/api/json/v2/provincias')
}
getMunicipios(cod_prov:string){
return this.http.get(`https://www.el-tiempo.net/api/json/v2/provincias/${cod_prov}/municipios`)
}
getDataMunicipio(cod_prov:string,id_muni:string){
return this.http.get(`https://www.el-tiempo.net/api/json/v2/provincias/${cod_prov}/municipios/${id_muni}`)
}
}
general.component.html:
<div class="contianer mt-5 m-sm-5">
<div class="table-responsive">
<table class="table table-striped table-dark" *ngIf="!loading_data">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Comunidad</th>
<th scope="col">Provincia</th>
<th scope="col">Muicipio</th>
<th scope="col">Prediccion</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of data_mun">
<th scope="row">{{data.CODPROV}}</th>
<td>{{data.comunidad}}</td>
<td>{{data.provincia}}</td>
<td>{{data.municipio}}</td>
<td>{{data.pronostico}}</td>
</tr>
</tbody>
</table>
</div>
</div>
我认为我没有遵循最佳实践,将不胜感激。
谢谢大家
解决方法
这是StackBlitz链接: https://stackblitz.com/edit/nested-api-calls-forkjoin?file=src/app/app.component.ts
首先,我建议为所有端点创建接口,因为这是打字稿的强大功能,因为它知道您将获取哪种数据,因此您会从IDE中获得很多帮助。
我导出了一些端点接口以查看其工作方式:
export interface Municipios {
breadcrumb: {
name: string;
title: string;
url: string;
}[];
codprov: string;
keywords: string;
metadescripcion: string;
municipios: Municipio[];
provincia: string;
title: string;
}
在您的服务中,它将是这样。
getMunicipios(cod_prov: string): Observable<Municipios> {
return this.http.get<Municipios>(
`https://www.el-tiempo.net/api/json/v2/provincias/${cod_prov}/municipios`
);
}
第二个:服务,接口和类的命名约定为PascalCase
因此eltiempoDataService
将是EltiempoDataService
第三:由于您需要来自第一个API请求结果的第一个数组中的数据,因此您可以使用forkJoin
来简单地将所有请求一起发送,当它们准备就绪时,您可以使用答案。
forkJoin:https://www.learnrxjs.io/learn-rxjs/operators/combination/forkjoin
因此,您可以在此处创建一个包含省份且可观察到的下一个数据的数组。
this.loading_data = true;
const provinciasGetMunicipiosObservables: {
province: Province;
getMunicipios: Observable<Municipios>;
}[] = [];
const getDataMunicipioObservables: { // This is for second wave of API Calls
province: Province;
municipios: Municipios;
getDataMunicipio: Observable<DataMunicipio>;
}[] = [];
provincias.forEach(province => {
/***************************
**** Creating Array of province and getMunicipios observable
***************************/
provinciasGetMunicipiosObservables.push({
province,getMunicipios: this.getMunicipios(province.CODPROV)
});
});
当数组准备好时,您可以将其传递给forkJoin,当所有数组的结果准备好时,它将给出答案。
注意:因为我没有创建观察对象的绝对数组,所以我只需要map
观察对象,因此它会返回观察对象数组
observable内部的管道用于映射该特定Observable的答案,当它可以访问省时,我将其映射到Answer内部。
forkJoin(
provinciasGetMunicipiosObservables.map(x => {
return x.getMunicipios.pipe(
map(y => {
return {
province: x.province,getMunicipiosAnswer: y
};
})
);
})
)
.pipe(first())
.subscribe(municipiosArray => {
// Time to send Second Wave of API requests
}
您只需像以前一样重复该过程即可。
.subscribe(municipiosArray => {
municipiosArray.forEach(municipios => {
/***************************
**** Part two of data when we got getMunicipios
***************************/
let local_muni: any[] = municipios.getMunicipiosAnswer.municipios;
var random = Math.floor(Math.random() * local_muni.length);
let cod_ine_mun = local_muni[random]["CODIGOINE"]
.toString()
.substring(0,5);
/***************************
**** Creating second array for getting getDataMunicipio
***************************/
getDataMunicipioObservables.push({
municipios: municipios.getMunicipiosAnswer,province: municipios.province,getDataMunicipio: this.getDataMunicipio(
municipios.province.CODPROV,cod_ine_mun
)
});
});
/***************************
**** Send Requests with forkJoin
***************************/
forkJoin(
getDataMunicipioObservables.map(x => {
return x.getDataMunicipio.pipe(
map(y => {
return {
province: x.province,municipios: x.municipios,getDataMunicipioAnswer: y
};
})
);
})
).subscribe(arrayOfFinalData => {
// temproray array
const finalData: WeatherGeneral[] = [];
arrayOfFinalData.forEach(weatherData => {
const max = weatherData.getDataMunicipioAnswer.temperaturas.max;
const min = weatherData.getDataMunicipioAnswer.temperaturas.min;
const pronostico = `${max}/${min}`;
const weatherGeneral = new WeatherGeneral({
cod_prov: weatherData.province.CODPROV,comunidad: weatherData.province.COMUNIDAD_CIUDAD_AUTONOMA,municipio: weatherData.getDataMunicipioAnswer.municipio.NOMBRE,pronostico,provincia: weatherData.province.NOMBRE_PROVINCIA
});
finalData.push(weatherGeneral);
});
this.loading_data = false;
this.data_mun = [...finalData];
});
});
并随时询问是否不清楚。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。