【问题标题】:Component renders before NgOnInit finishes?组件在 NgOnInit 完成之前渲染?
【发布时间】:2018-09-19 18:54:38
【问题描述】:

我有一个组件,它对调用 api 的服务执行一些调用。组件在这些调用完成之前呈现,导致页面为空。

这是来自组件的代码:

import {Component, OnInit, OnDestroy} from '@angular/core';
import {AuthService} from '../services/auth.service';
import {AssignmentService} from '../services/assignment.service';
import {Assignment} from '../models/Assignment';
import {Request} from '../models/Request';
import {MeService} from '../services/me.service';
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
import {Router} from '@angular/router';
import {NavbarService} from '../services/navbar.service';

@Component({
  selector: 'app-newrequest',
  templateUrl: './newrequest.component.html',
  providers: [AssignmentService]
})
export class NewrequestComponent implements OnInit {
  me: MicrosoftGraph.User;
  assignments: Assignment[];
  requests: Request[] = [];
  ready = false;

  constructor(private meService: MeService,
              private authService: AuthService,
              private assignmentService: AssignmentService,
              private router: Router,
              public nav: NavbarService) {
  }

  ngOnInit() {
    this.nav.show();
    this.nav.element = 'newrequests';
    if (localStorage.getItem('loggedin') === 'yes') {
      this.meService.getMe().subscribe(data => {
          this.me = data;
        },
        error => {
          console.log(error);
        },
        () => this.assignmentService.getAssignments().subscribe(data => {
            this.assignments = data;
          },
          error => {
            console.log(error);
          },
          () => {
            this.setRequests();
          }));
    } else {
      this.router.navigate(['']);
    }
  }

  onLogout() {
    this.authService.logout();
  }

  onLogin() {
    this.authService.login();
  }

  private setRequests() {
    this.assignments.forEach(item => {
      if (this.me.mail.toLowerCase() === item.lecturer.toLowerCase()) {
        this.parseRequests(item.request, item.name);
      }
    });

    this.ready = true;
  }

  private parseRequests(toSplit, name) {
    const split = toSplit.split(',');

    split.forEach(item => {
      this.requests.push(new Request(item, name));
    });
  }
}

这是页面中的代码:

<app-navbar-component></app-navbar-component>
<div *ngIf="ready">
  <div *ngFor="let request of requests">
    <p class="lead">{{request.user}}</p>
  </div>
</div>

这是我的服务中的功能:

getAssignments() {
    return this.http.get(this.BASE_API_URL + '/assignments').catch(this.onError);
  }

我没有收到任何错误。请求已加载(通过 console.log 检查)。唯一的问题是页面在数据加载完成之前呈现。

有什么想法吗?

提前致谢!

【问题讨论】:

  • 是的,没错。 HTTP 请求是异步的,因此它不会等到完成。
  • 我该如何规避这个问题?我认为 *ngIf 会工作......
  • 规避什么?请求最终完成时是否呈现数据?
  • 如果你不想在收到数据之前渲染页面,你可以使用router resolve guard。
  • 请求完成后组件不渲染。

标签: angular typescript rxjs ngoninit


【解决方案1】:

是的,由于服务调用是异步的,调用订阅时数据不会立即到达。

但是在您的代码中,一旦数据到达,您并没有将 ready 变量设置为 true。所以你在页面上看不到任何数据。获取数据后设置为true

this.me = data;
this.ready =true;

或通过安全导航操作符处理。

【讨论】:

  • 感谢您的帮助。我认为你监督了准备好的部分。我在 setRequests() 函数中将 ready 设置为 true。
  • 是的。我注意到,当我在您提到的地方设置为 true 时,它​​在组件中变为 true。然而,这还为时过早。它使用的数据到那时还没有加载。我需要作业数据。
  • 在subscribe里面调用setrequests
  • 不幸的是没有改变任何东西
  • 我确定你的方法 parseRequest 有问题。只需检查您的数组是否有数据
【解决方案2】:

您是否尝试过使用解析?

创建一个解析器,命名为 assignments-details.resolver.ts

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import {MeService} from '../services/me.service';

@Injectable()
export class AssignmentsDetailsResolver implements Resolve<any> {

  constructor(api: MeService){}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
   return this.api.getAssignments();
  }

}

然后在你的路由配置中这样做

{
  path: 'your_path',
  component: NewrequestComponent,
  resolve: { AssignmentsDetails: AssignmentsDetailsResolver }
}

然后确保在您的 NewrequestComponent 上导入 ActivatedRoute

import { ActivatedRoute } from '@angular/router'

在你的构造函数中这样称呼它

 constructor(private meService: MeService,
              private authService: AuthService,
              private assignmentService: AssignmentService,
              private router: Router,
              public nav: NavbarService,
              private activateRoute: ActivatedRoute) {

   this.activateRoute.data.subscribe((response) => {
       //to get the response
       console.log(response.AssignmentsDetails);
     });
  }

还要确保在模块的 provider 属性中注册“AssignmentsDetailsResolver”。

希望对你有所帮助。

【讨论】:

  • 这里的resolve方法就是这个问题的准确答案。
猜你喜欢
  • 2021-05-18
  • 2021-10-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 1970-01-01
  • 1970-01-01
  • 2017-04-04
  • 1970-01-01
相关资源
最近更新 更多