Angular 6: 在调用 HTTP 请求后未设置 class 的属性

Angular 6: not set properties of class after calling HTTP-request

我有带标签的组件(ProfileComponent 是其他组件的父组件)。我想使用 ProjekteingangComponent 中的服务(角色和项目)从服务器加载数据。

我为此函数编写了加载数据(loadRoles()loadProjects())并在 ngOnInit() 上调用它,但问题是 value 没有设置 this.rolesthis.projectsHere and here 在浏览器中输出到控制台。

正如您在 loadRoles()loadProjects() 中的输出 value 中看到的那样,在错误之后写入。我该如何改进并正确设置 ngOnInit() 中的 this.projectsthis.roles

projekteingang.component.ts:

import {Component, Input, OnInit} from '@angular/core';
import {ProfileComponent} from '../profile.component';
import {UserOfferMapping} from "../../../_models/UserOfferMapping";
import {UseroffermappingService} from "../../../_services/useroffermapping.service";
import {Userproject} from "../../../_models/Userproject";
import {Userrole} from "../../../_models/userrole";
import {UserprojectService} from "../../../_services/userproject.service";
import {UserroleService} from "../../../_services/userrole.service";
import {ProjectUtils} from "../../../utils/ProjectUtils";

@Component({
  selector: 'app-projekteingang',
  templateUrl: './projekteingang.component.html',
  styleUrls: ['./projekteingang.component.css']
})
export class ProjekteingangComponent implements OnInit {
  public userOfferMapping: any[];
  public  userId: number;
  public offerDataSource: any[] = [];
  public projects: Userproject[] = [];
  public roles: Userrole[] = [];
  constructor(
    private profileComponent: ProfileComponent,
    private useroffremappingService: UseroffermappingService,
    private userProjectService: UserprojectService,
    private userRoleService: UserroleService,) {
  }

  loadRoles() {
    this.userRoleService.getAllRoles().toPromise().then((value) => {
      console.log("value roles");
      console.log(value);
      this.roles = value;
    });
  }

  loadProjects(){
    this.userProjectService.getAllProjects().toPromise().then((value) => {
      console.log("value projects");
      console.log(value);
      this.projects = value;
    });
  }

  ngOnInit() {
    this.userId = this.profileComponent.currentUser.id;
    this.loadProjects();
    this.loadRoles();
    console.log("roles ngoinit");
    console.log(this.roles);
    console.log("projects ngoinit");
    console.log(this.projects);
    this.loadUserOfferMappings();
  }

  findProjectByID(id) {
    let project = null;
    this.projects.map(elem => {
      if (elem.id == id) {
        project = elem;
      }
    })
    return project;
  }

  findRoleByID(id) {
    let role = null;
    this.roles.map(elem => {
      if (elem.id == id) {
        role = elem;
      }
    })
    return role;
  }

  loadUserOfferMappings() {
    console.log("roles in func");
    console.log(this.roles);
    console.log("projects in func");
    console.log(this.projects);
    this.useroffremappingService.getAllUseroffermappingsByUserId(this.userId).subscribe(value => {
      console.log("Useroffermapping");
      console.log(value);
      this.userOfferMapping = value;
      value.map(elem => {
        console.log(elem);
        let project = this.findProjectByID(elem.projectId);
        let role = this.findRoleByID(elem.roleId);
        console.log(role);
        console.log(project);
        this.offerDataSource.push({
          projectId: elem.projectId,
          roleId: elem.roleId,
          projectName: project.name,
          roleName: role.name,
          roleTooltip: role.description
        });
      })
    });
  }

  get profile() {
    return this.profileComponent;
  }

}

profile.component.html:

  <mat-tab-group>
    <-- ... -->
    <-- another tabs -->
    <-- ... -->
    <mat-tab label="Projekt eingang">
      <app-projekteingang></app-projekteingang>
    </mat-tab>
</mat-tab-group>

我看到很多被误解的事情:

  1. 不需要使用.toPromise()

改用.subscribe(...)

loadProjects(){
    this.userProjectService.getAllProjects().subscribe((value) => {
      console.log("value projects");
      console.log(value);
      this.projects = value;
    });
  }
  1. 您正在获取异步数据

您必须等待它们才能使用它们。

  1. 您的关键代码需要所有 3 个调用的答案

所以你必须将这段代码提取到另一个方法,在每次数据接收时调用(检查你是否有所有数据)

loadRoles() {
  this.userRoleService.getAllRoles().subscribe((value) => {
    console.log("value roles");
    console.log(value);
    this.roles = value;
    this.feedOfferDataSource();
  });
}

loadProjects(){
  this.userProjectService.getAllProjects().subscribe((value) => {
    console.log("value projects");
    console.log(value);
    this.projects = value;
    this.feedOfferDataSource();
  });
}

loadUserOfferMappings() {

  console.log("roles in func");
  console.log(this.roles);
  console.log("projects in func");
  console.log(this.projects);
   this.useroffremappingService.getAllUseroffermappingsByUserId(this.userId).subscribe(value => {
    console.log("Useroffermapping");
    console.log(value);
    this.userOfferMapping = value;
    this.feedOfferDataSource();
  }
}

feedOfferDataSource() {
  if(!this.projects || !this.roles || !this.userOfferMapping) return;

  this.offerDataSource = this.userOfferMapping.map(elem => {
    console.log(elem);
    let project = this.findProjectByID(elem.projectId);
    let role = this.findRoleByID(elem.roleId);
    console.log(role);
    console.log(project);
    return {
      projectId: elem.projectId,
      roleId: elem.roleId,
      projectName: project.name,
      roleName: role.name,
      roleTooltip: role.description
    };
}
  1. 您使用了 map 而没有使用它的值

getAllRolesgetAllProjectsgetAllUseroffermappingsByUserId 是三个独立的异步调用。一个不能保证三个完成的先后顺序

现在函数 loadUserOfferMappings 实际上取决于为角色和项目获取的数据。因此,这意味着 getAllUseroffermappingsByUserId 应仅在项目和角色已获取后调用。

现在有多种方法可以解决这个问题:

  1. 最新手的方法是在使用getAllUseroffermappingsByUserId;

  2. 之前检查角色和项目是否可用
  3. 更明智的方法是在仅解析角色和项目调用后实际调用 loadUserOfferMappings 方法。(使用可观察对象或承诺任何内容)

  4. 另一种方法是为您的 promise 调用保持加载状态。 例如异步调用处于加载、加载或错误状态。因此,仅当 getRolesgetProjects 处于加载状态时才调用 getAllUseroffermappingsByUserId