【问题标题】:how to wait service load data complete?如何等待服务加载数据完成?
【发布时间】:2019-09-18 14:22:17
【问题描述】:

我想在组件构造函数中从 Angular 服务加载数据,并使用这些数据在 ngOnInit() 函数中更新 UI。

我正在使用 async-await 功能来实现它。

很遗憾,它不起作用。

这是我的组件源代码:

import { Component, OnInit } from '@angular/core';
import {MonthlyCalendar} from './monthly-calendar';
import { MonthlyCalendarService } from './monthly-calendar.service';
import { resolve } from 'url';
@Component({
  selector: 'app-table',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.css']
})
export class TableComponent implements OnInit {
  monthlyCalendar: MonthlyCalendar;
  constructor(private monthlyCalendarService: MonthlyCalendarService) {
    this.monthlyCalendar = null;
    console.log('t0:' + new Date());
    this._getData();

    console.log('t2:' + new Date());
  }

  ngOnInit() {
    console.log('t3:' + new Date());
    console.log(this.monthlyCalendar);
  }
  async _getData() {

    await this.monthlyCalendarService.getMonthlyCalendar(null, null)
    .then((data: MonthlyCalendar) => {
      console.log('t1:' + new Date());
      this.monthlyCalendar = data;
    })
    .catch ((err: Error) => {
      alert(err.stack);
    });
  }
}

这是我的服务源代码:

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';
import { MonthlyCalendar } from './monthly-calendar';
import { resolve, reject } from 'q';

@Injectable({
  providedIn: 'root'
})
export class MonthlyCalendarService {

  constructor(private http: HttpClient) { }
  getMonthlyCalendar(year: number, month: number): Promise<object> {
    const params = new HttpParams();
    if (year != null) {
      params.set('year', year.toString());
    }
    if (month != null) {
      params.set('month', month.toString());
    }
    return this.http.get('backend/getMonthlyCalendar.php', {params}).toPromise();
  }
}

这是我的component.html

<table>
  <theader></theader>
  <tbody></tbody>
</table>

我附上了屏幕转储供您参考。

【问题讨论】:

  • 你可以添加你的模板代码吗?
  • 你的意思是component.html吗?
  • 是的,你使用的代码monthlyCalendar
  • 目前,我想确保this.monthlyCalendar在ngOnInit()之前不为空,所以component.html只是初始内容。
  • 如果我说你不能阻止渲染怎么办。而是将数据检索移动到父组件并使用 ngIf 仅在数据已解析时才呈现组件。其他在此组件中使用 ngIf 并在数据加载时使用某种加载动画。将异步调用或计算量大的操作移出构造函数。

标签: angular async-await


【解决方案1】:

您可以使用解析器在组件加载之前加载数据,它不会加载路由,直到数据请求被解析下面是解析器的一些示例

https://codeburst.io/understanding-resolvers-in-angular-736e9db71267

https://alligator.io/angular/route-resolvers/

所以首先创建一个解析器

import { Injectable } from '@angular/core';

import { Resolve } from '@angular/router';

import { Observable } from 'rxjs';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/delay';

@Injectable()
export class CalendarResolver implements Resolve<Observable<string>> {
  constructor(private monthlyCalendarService: MonthlyCalendarService) {}

  resolve() {
    return this.monthlyCalendarService.getMonthlyCalendar(null, null);
  }
}

然后将此解析器添加到您的路线中

import { CalendarResolver } from './claendar.resolver';

   {
    path: 'yourpath',
    component: yourcomponent,
    resolve: { calander: CalendarResolver }
    }

将解析器添加到模块的 providers 数组中

然后在你的组件中

   constructor(private activatedRoute: ActivatedRoute)

   ngOnInit(){
    this.monthlyCalander= this.route.snapshot.data['calander'];
   }

【讨论】:

  • 提示node_modules/rxjs/Observable没有导出成员'Observable'。我正在使用角度 8。
  • @TheKNVB 从最新版本使用import { Observable } from 'rxjs'
  • 我不确定这个你可以添加你的问题的 stackblitz 例子
  • 这里是解析器的工作演示stackblitz.com/edit/angular-resolver-demo
  • 我尝试为主页执行此操作,但我看不到如何更改(预先存在的?)解析器,如果我添加另一条带有路径的路由:'' for home 那么它“有效“但是我的应用程序随后被复制了..就像我看到所有元素两次一样,页脚和页眉..我有一个具有同构的新样板角度安装,遵循官方安装步骤..在 nextjs 中,它就像一个文件中的 5 行代码。 .. ;)
【解决方案2】:

您可以为此使用解析器

@Injectable()
export class MyResolver implements Resolve<SomeClass[]> {
    constructor(private myService: MyService) {
    }

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<SomeClass[]> {
        return this.myService.getAll().pipe(first());
    }
}

在您的路由器中,您可以注册解析器。

        {
            path: 'somepath',
            component: MyComponent,
            resolve: {
                objects: MyResolver ,
            }
        },

然后您可以在组件中访问解析后的数据,如下所示。

ngOnInit(): void {
    this.route.data.subscribe((data: any) => {
        this.objects = data['objects'];
    });
}

【讨论】:

    【解决方案3】:

    你必须在构造函数中像这样更改代码

    this._getData().then(() =>  
          console.log('t2:' + new Date()
          ))
    

    【讨论】:

    • ngOnInit() 不等待指定的代码。
    • 这段代码不会等待完成执行。 then 方法在_getDate 执行后自动触发。您可以将 _getDate 之后想要执行的任何代码放入 then 方法中
    【解决方案4】:

    Angular 有一个非常好的模块 HTTPClientModule。这是建立在 RxJS Observable 包之上的。

    HTTPClientModule的get等方法,返回observable,我们可以在组件中订阅,通知view更新DOM。

    请看官方documentation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多