嵌套可观测对象和以角度加载内容的问题

如何解决嵌套可观测对象和以角度加载内容的问题

我开始使用天气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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-