Angular2:在渲染组件之前如何加载数据?

16 浏览
0 Comments

Angular2:在渲染组件之前如何加载数据?

在组件渲染之前,我正在尝试从我的API中加载一个事件。目前,我正在使用我的API服务,我从组件的ngOnInit函数中调用它。

我的EventRegister组件:

import {Component, OnInit, ElementRef} from "angular2/core";
import {ApiService} from "../../services/api.service";
import {EventModel} from '../../models/EventModel';
import {Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig, RouteParams, RouterLink} from 'angular2/router';
import {FORM_PROVIDERS, FORM_DIRECTIVES, Control} from 'angular2/common';
@Component({
    selector: "register",
    templateUrl: "/events/register"
    // provider array is added in parent component
})
export class EventRegister implements OnInit {
    eventId: string;
    ev: EventModel;
    constructor(private _apiService: ApiService, 
                        params: RouteParams) {
        this.eventId = params.get('id');
    }
    fetchEvent(): void {
        this._apiService.get.event(this.eventId).then(event => {
            this.ev = event;
            console.log(event); // 有值
            console.log(this.ev); // 有值
        });
    }
    ngOnInit() {
        this.fetchEvent();
        console.log(this.ev); // 没有值
    }
}

我的EventRegister模板:


    Hi this sentence is always visible, even if `ev property` is not loaded yet    
        I should be visible as soon the `ev property` is loaded. Currently I am never shown.
        {{event.id }}

我的API服务:

import "rxjs/Rx"
import {Http} from "angular2/http";
import {Injectable} from "angular2/core";
import {EventModel} from '../models/EventModel';
@Injectable()
export class ApiService {
    constructor(private http: Http) { }
    get = {
        event: (eventId: string): Promise => {
            return this.http.get("api/events/" + eventId).map(response => {
                return response.json(); // 有值
            }).toPromise();
        }     
    }     
}

组件在ngOnInit函数中的API调用完成之前就被渲染了。所以我从视图模板中无法看到事件ID。看起来像是一个异步问题。我期望在设置evEventRegister组件)属性之后,绑定会做一些工作。可惜当属性被设置时,它不会显示带有*ngIf="ev"标记的div

问题:我使用的方法好吗?如果不好,加载数据在组件开始渲染之前的最佳方法是什么?

注意:在这个angular2教程中使用了ngOnInit方法。

编辑:

两个可能的解决方案。第一个是放弃fetchEvent,只在ngOnInit函数中使用API服务。

ngOnInit() {
    this._apiService.get.event(this.eventId).then(event => this.ev = event);
}

第二个解决方案,就像给出的答案一样。

fetchEvent(): Promise {
    return this._apiService.get.event(this.eventId);
}
ngOnInit() {
    this.fetchEvent().then(event => this.ev = event);
}

0
0 Comments

Angular2: 如何在渲染组件之前加载数据?

在Angular2+中,您可以使用解析器(Resolvers)来预取数据,解析器能在组件完全加载之前处理数据。有许多情况下,您只想在发生某些特定事件时加载组件,例如只有在用户已登录时导航到仪表板,这种情况下解析器非常方便。下面是我为您创建的一个简单图表,展示了如何使用解析器将数据发送到组件。

![enter image description here](https://i.stack.imgur.com/eHzu2.jpg)

将解析器应用到您的代码中非常简单,我为您创建了代码片段,以便查看如何创建解析器:

import { Injectable } from '/core';
import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '/router';
import { MyData, MyService } from './my.service';
@Injectable()
export class MyResolver implements Resolve {
  constructor(private ms: MyService, private router: Router) {}
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise {
    let id = route.params['id'];
    return this.ms.getId(id).then(data => {
      if (data) {
        return data;
      } else {
        this.router.navigate(['/login']);
        return;
      }
    });
  }
}

在模块中:

import { MyResolver } from './my-resolver.service';
@NgModule({
  imports: [
    RouterModule.forChild(myRoutes)
  ],
  exports: [
    RouterModule
  ],
  providers: [
    MyResolver
  ]
})
export class MyModule { }

您可以在组件中这样访问它:

ngOnInit() {
    this.route.data
      .subscribe((data: { mydata: myData }) => {
        this.id = data.mydata.id;
      });
  }

在路由中(通常在app.routing.ts文件中)可以这样配置:

{path: 'yourpath/:id', component: YourComponent, resolve: { myData: MyResolver}}

我认为您错过了在路由配置的Routes数组中添加条目(通常在app.routing.ts文件中):{path: 'yourpath/:id', component: YourComponent, resolve: { myData: MyData}},这不应该覆盖所有部分,但我同意,这样回答更全面,所以我添加了... 谢谢。

请纠正最后一部分,路由中的resolve参数应该指向解析器本身,而不是数据类型,即resolve: { myData: MyResolver }

MyData是在MyService中定义的模型对象吗?

这个解决方案适用于在页面加载之前获取数据,但不适用于检查已登录的用户或用户角色。对于这种情况,您应该使用守卫(Guards)。

0
0 Comments

在Angular 2中,有一个常见的问题是在组件渲染之前如何加载数据。在本文中,我们将讨论这个问题的原因以及解决方法。

问题的原因是Angular的单向数据流规则禁止在组件视图组合之后更新视图。这意味着我们不能在视图渲染之前加载数据。在Angular 1中,有一个解决方法是在UI上使用条件渲染。只有当isDataLoaded为true时,页面才会被渲染。然而,这个解决方法在Angular 2及以上版本中不再适用。

解决方法是使用变化检测策略(ChangeDetectionStrategy)来实现双向绑定。默认情况下,Angular使用的是ChangeDetectionStrategy.Default。我们可以将其更改为ChangeDetectionStrategy.Push,以实现双向绑定。这样,数据加载完成后,页面会自动更新并渲染。

这个解决方法已经在Angular 6中得到验证,可以正常工作。现在,我们可以在组件渲染之前加载数据,并在加载完成后更新页面。

总结起来,解决这个问题的方法是使用变化检测策略来实现双向绑定。通过将ChangeDetectionStrategy设置为Push,可以在组件渲染之前加载数据,并在加载完成后自动更新页面。这个解决方法已经在Angular 6中得到验证,并且可以成功解决问题。

0
0 Comments

在Angular2中,有时候我们需要在组件渲染之前加载数据。在这个问题中,问题的原因是在调用this.fetchEvent()之后立即执行console.log(this.ev)语句时,fetchEvent()方法并没有执行完成,只是被调度了,因此console.log(this.ev)语句并没有得到正确的值。

解决方法是将fetchEvent()方法改为返回一个Promise对象,并在ngOnInit()方法中等待Promise对象完成。这样可以确保在组件渲染之前数据已经加载完毕。

另外,可以在模板中使用*ngIf指令来包裹整个模板内容,只有在数据加载完成后才显示模板内容。

总结起来,解决这个问题的方法有两种:

1. 将fetchEvent()方法改为返回Promise对象,并在ngOnInit()方法中等待Promise对象完成。

2. 使用*ngIf指令在模板中判断数据是否加载完成,只有在数据加载完成后才显示模板内容。

在这个问题中,使用第一种方法解决了问题,并得到了满意的结果。不过,有人认为这种方法只是一个权宜之计,而不是一个正确的解决方案。在Angular 5中应该有更好的解决方法。

对此,有人表示不理解为什么会有人对这种解决方法提出异议,认为这两种方法都是完全可以接受的。

总之,从这个问题中可以看出,为了在组件渲染之前加载数据,可以使用返回Promise对象的方法或者使用*ngIf指令来判断数据是否加载完成。

0