【问题标题】:Fetch(HTTP-Get) multiple class objects in Angular在Angular中获取(HTTP-Get)多个类对象
【发布时间】:2019-12-09 12:56:12
【问题描述】:

首先,用我的实际代码解释这有点令人困惑,所以我试图用一个更小的例子来简化这个问题。

假设我的项目从我的服务器中的 2 个不同表接收数据,employeeDetailsemployeeNames

employeeNames:此表包含三列,employeeNumberfirstNamelastName。顾名思义,此表包含所有员工的列表,包括他们的名字和姓氏以及唯一的员工编号。

employeeDetails: 这个表是我从我的网站 httpGet 和 httpPost 数据的地方。例如,假设该表具有以下字段:

  • employee:以员工编号为输入
  • qualifications:让用户以字符串形式输入各种资格
  • 主管:获取主管的员工编号,而不是姓名
  • manager:获取经理的员工编号,而不是姓名

虽然后端是这种情况,但前端的 employeeDetails 接口有更多成员。这就是棘手的地方。

在前端,角度界面是这样的:

export interface employeeDetails
{
    employee: number;
    qualifications: string;
    supervisor: number;
    manager: number;
    employeeName: string;
    supervisorName: string;
    managerName: string;
}

所以,我使用 httpGet 从后端 api 获取数据,一旦我收到这两个表,我就有一个函数来填充 employeeDetails 接口中的额外字段。

控制器

[HttpGet("[action]")]
public IActionResult getEmployeeNames()
{
        using (var empApp= new EmployeeTable())
        {
            var empNames = new List<employeeNames>();
            empNames = empApp.employeeNames.ToList();
            return Json(empNames);
        }
}

[HttpGet("[action]")]
public IActionResult employeeDetails()
{
        using (var empApp= new EmployeeTable())
        {
            var empDetails = new List<employeeDetails>();
            empDetails = empApp.employeeDetails.ToList();
            return Json(empDetails);
        }
}

服务

  getEmployeeNames(): Observable<employeeNames[]> {
    return this.http.get<employeeNames[]>(this.baseUrl + 'api/employeecontroller/getEmployeeNames')
    .pipe(catchError(this.handleError('getItems', [])));
  }

  getEmployeeDetails(): Observable<employeeDetails[]> {
    return this.http.get<employeeDetails[]>(this.baseUrl + 'api/employeecontroller/getEmployeeDetails')
    .pipe(catchError(this.handleError('getItems', [])));
  }

组件

getEmployeeInfo() {
    this.employeeService.getEmployeeNames()
      .subscribe(data => this.employeeNames = data);
    this.employeeService.getEmployeeDetails()
      .subscribe(data => this.employeeDetails = data);

    fillEmployeeDetails();
}

fillEmployeeDetails() {
    this.employeeDetails.forEach(elem => {
        let emp = this.employeeNames.find(employee => {
            return (employee.employeeNumber === elem.employeeNumber);
        });
        let sup = this.employeeNames.find(supervisor => {
            return (supervisor.employeeNumber === elem.supervisor);
        });
        let man = this.employeeNames.find(manager=> {
            return (manager.employeeNumber === elem.manager);
        });

        elem.employeeName = emp.firstName + " " + emp.lastName;
        elem.supervisorName= sup.firstName + " " + sup.lastName;
        elem.managerName= man.firstName + " " + man.lastName;

    });
}

因此,当我尝试调用此函数时,它会失败。 原因是该函数甚至在获取整个employeeNames 表之前就已被调用。如果没有获取表,.find() 将返回许多员工编号的空值,因此,我的函数不会按预期返回结果。

我的问题

我应该使用 async/await 和 .toPromise() 并避免订阅服务以等待获取数据,还是有更好的方法?

非常感谢任何帮助或想法。谢谢!

【问题讨论】:

    标签: angular typescript async-await angular-promise http-get


    【解决方案1】:

    您必须订阅 observable 才能发起 HTTP 请求。 此外,您不能像在 sn-p 中那样调用 this.fillEmployeeDetails();,因为请求是异步的,并且数据需要一些时间才能返回 - 但是,您调用 this.fillEmployeeDetails 的代码行将在之后立即执行触发请求。

    当数据返回时,订阅内部的回调函数会以请求响应作为参数被调用。您必须在订阅中调用this.fillEmployeeDetails();,因为您在那里接收数据。

    但是你怎么知道两个请求是否已经返回,即你能启动你的fill...函数吗?

    最佳解决方案是使用 rxJs 运算符,例如 forkJoin,在这种情况下,它的行为类似于 Promise.all()。也就是说,它仅在所有可观察对象(在您的情况下为请求)都执行完毕时才会触发其在订阅中的回调。

    基本上,您的组件代码应该如下所示:

    getEmployeeInfo() { // requests extracted in constants for readability
        const employeeNamesRequest = this.employeeService.getEmployeeNames();
        const employeeDetailsRequest = this.employeeService.getEmployeeDetails();
    
        forkJoin([employeeNamesRequest, employeeDetailsRequest])
            .subscribe(data => {
                this.employeeNames = data[0];
                this.employeeDetails = data[1];
                this.fillEmployeeDetails();
            })
    }
    
    fillEmployeeDetails() {
        this.employeeDetails.forEach(elem => {
            let emp = this.employeeNames.find(employee => {
            return (employee.employeeNumber === elem.employeeNumber);
        });
        let sup = this.employeeNames.find(supervisor => {
            return (supervisor.employeeNumber === elem.supervisor);
        });
        let man = this.employeeNames.find(manager=> {
            return (manager.employeeNumber === elem.manager);
        });
    
        elem.employeeName = emp.firstName + " " + emp.lastName;
        elem.supervisorName= sup.firstName + " " + sup.lastName;
        elem.managerName= man.firstName + " " + man.lastName;
    
        });
    }
    

    【讨论】:

    • 我一定会尝试这种方法。此外,我尝试了其他一些我认为应该可行的方法,但它似乎存在一些问题。这是我认为可行的另一种方法。如果我的方法有问题,请告诉我:async getEmployeeInfo() { this.employeeNames = await this.employeeService.getEmployeeNames().toPromise(); this.employeeDetails = await this.employeeService.getEmployeeDetails().toPromise(); this.fillEmployeeDetails(); }
    • 是的,总而言之,我认为您的方法应该有效 - 即使它不是最理想的并且与 angular 所提倡的背道而驰。请求是否以状态码 200 执行?您在执行该代码时是否遇到任何错误?您是否尝试在请求执行后设置调试器/console.log 以查看返回值是什么?
    • 抱歉耽搁了,这几天我都出去了。无论如何,我尝试了你的方法,它就像一个魅力,使用 .toPromise() 的方法也有效,但是,正如你提到的,我知道它不是有角度的方式,所以我使用了 forkJoin()。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2018-12-05
    • 1970-01-01
    • 2020-12-24
    • 2018-11-04
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    • 2017-12-04
    相关资源
    最近更新 更多