当前位置: 首页 > 知识库问答 >
问题:

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

高恺
2023-03-14

我试图在呈现组件之前从API加载事件。目前我正在使用我的API服务,我从组件的ngOnInit函数调用该服务。

我的Event寄存器组件:

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); // Has a value
            console.log(this.ev); // Has a value
        });
    }

    ngOnInit() {
        this.fetchEvent();
        console.log(this.ev); // Has NO value
    }
}

我的EventRegister模板

<register>
    Hi this sentence is always visible, even if `ev property` is not loaded yet    
    <div *ngIf="ev">
        I should be visible as soon the `ev property` is loaded. Currently I am never shown.
        <span>{{event.id }}</span>
    </div>
</register>

我的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<EventModel> => {
            return this.http.get("api/events/" + eventId).map(response => {
                return response.json(); // Has a value
            }).toPromise();
        }     
    }     
}

组件在ngOnInit函数中的API调用完成获取数据之前呈现。所以我从来没有看到我的视图模板中的事件ID。所以看起来这是一个ASYNC问题。我期望在设置了ev属性后,绑定evEvent寄存器组件)来完成一些工作。可悲的是,当属性被设置时,它不显示用*ngIF="ev"标记的div

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

注:本angular2教程使用了Ngonit方法。

编辑:

两种可能的解决方案。首先是放弃felchEvents,只在ngOnInit函数中使用API服务。

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

第二个解决方案。我喜欢给出的答案。

fetchEvent(): Promise<EventModel> {
    return this._apiService.get.event(this.eventId);
}

ngOnInit() {
    this.fetchEvent().then(event => this.ev = event);
}

共有3个答案

董琦
2023-03-14

我发现一个很好的解决方案是在UI上执行以下操作:

<div *ngIf="isDataLoaded">
 ...Your page...
</div

只有当:isDataLoaded为true时,才会呈现页面。

令狐钧
2023-03-14

您可以在Angular2中使用Resolvers预取数据,Resolvers在您的组件完全加载之前处理您的数据。

在许多情况下,您希望仅在发生某些事情时加载组件,例如,仅当用户已登录时才导航到仪表板,在这种情况下,解析程序非常方便。

请看我为您创建的简单图表,了解如何使用解析器将数据发送到组件。

将解析器应用于代码非常简单,我为您创建了代码段,以了解如何创建解析器:

import { Injectable } from '@angular/core';
import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router';
import { MyData, MyService } from './my.service';

@Injectable()
export class MyResolver implements Resolve<MyData> {
  constructor(private ms: MyService, private router: Router) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<MyData> {
    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}}
////
唐阳飇
2023-03-14

更新

>

  • 如果使用路由器,则可以使用生命周期挂钩或解析器延迟导航,直到数据到达。https://angular.io/guide/router#milestone-五路卫

    要在根组件的初始呈现之前加载数据,可以使用初始化器APP\u将从后端呈现的参数传递到angular2引导方法

    原创

    this.fetchEvent()之后执行console.log(this.ev),这并不意味着fetchEvent()调用已完成,这只意味着它已被调度。当执行console.log(this.ev)时,甚至没有调用服务器,当然也没有返回值。

    将返回Promise的参数更改为:

         fetchEvent(){
            return  this._apiService.get.event(this.eventId).then(event => {
                this.ev = event;
                console.log(event); // Has a value
                console.log(this.ev); // Has a value
            });
         }
    

    更改ngOnInit()以等待promise完成

        ngOnInit() {
            this.fetchEvent().then(() =>
            console.log(this.ev)); // Now has value;
        }
    

    这实际上不会为您的用例买很多东西。

    我的建议是:将整个模板包装在一个中。

    ngOnInit()中

        isDataAvailable:boolean = false;
    
        ngOnInit() {
            this.fetchEvent().then(() =>
            this.isDataAvailable = true); // Now has value;
        }
    

  •  类似资料:
    • 问题内容: 我被困住了。我在单独的文件上有几个单独的组件。如果我在main.jsx中渲染它们,如下所示: 一切正常,但我想知道这是否是一个好习惯?也许可以做一些像只有一个ReactDom.render这样的事情: 我尝试了各种LandingPageBox变量,以某种方式包括了其他两个组件,但没有运气。它们有时在页面外渲染,依此类推。我认为应该看起来像这样: 但是此代码仅呈现PageTop和Page

    • 我正在使用Vue路由器和基于文件的组件。我打电话给其中一条路线并获取一个参数(slug),该参数使用axios从API获取json。 我使用“组件内保护”来实现这一点,使用名为beforeRouteEnter的方法。我正在将axios的响应传递到下一个方法。 这是可行的,但是,Vue在设置数据之前呈现视图。这将生成

    • 问题内容: 我正在努力寻找一种方法来做到这一点。在父组件中,模板描述了及其元素,但将渲染委托给了另一个组件,如下所示: 每个myResult组件都呈现其自己的标签,基本上是这样的: 我之所以没有将其直接放在父组件中(避免需要使用myResult组件)是因为myResult组件实际上比此处显示的要复杂,因此我想将其行为放在单独的组件和文件中。 产生的DOM看起来很糟。我相信这是因为它无效,因为它只能

    • 问题内容: 我有一个react组件,需要 在渲染之前 预先知道其尺寸 。 当我在jquery中制作一个小部件时,我可以在构建组件时提前获取容器的宽度。 这些容器的尺寸以及页面上的其他许多容器都在CSS中定义。谁在React中定义组件的高度,宽度和位置?我已经习惯了CSS并能够访问它。但是在React中,似乎我只能在组件渲染后访问该信息。 问题答案: 如前所述,在将元素呈现为DOM之前,您无法获得任

    • 问题内容: 你能告诉我如何在react js中渲染列表吗?我喜欢这样 问题答案: 您可以通过两种方式进行操作: 第一: 第二: 直接在返回中编写map函数

    • 所以基本上我有一个导航栏,可以在路线之间切换。当页面加载时,默认情况下会转到/home,但实际上不会呈现所提供的应用程序组件。我必须单击将您带到/主页的按钮才能渲染此内容。 我使用Redux的反应路由器。 这是我的浏览器路由器: 有什么建议吗?