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); // 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();
        }     
    }     
}

компонент отображается перед вызовом API в ngOnInit функция выполнена для извлечения данных. Поэтому я никогда не вижу идентификатор события в своем представлении шаблон. Похоже, это асинхронная проблема. Я ожидал связывания ev (EventRegister компонент), чтобы сделать некоторую работу после ev свойство установлено. К сожалению, он не показывает div С пометкой *ngIf="ev" когда свойство будет установлено.

вопрос: я использую хороший подход? Если нет; каков наилучший способ загрузки данных до начала рендеринга компонента?

Примечание: на ngOnInit подход используется в данной angular2 учебник.

EDIT:

два возможных решения. Сначала нужно было бросить fetchEvent и просто используйте службу API в

3 ответов


обновление

оригинал

, когда console.log(this.ev) выполняется после this.fetchEvent();, это не значит fetchEvent() вызов выполнен, это означает только, что он запланирован. Когда console.log(this.ev) выполняется, вызов на сервер даже не сделан и, конечно, еще не вернул значение.

изменить fetchEvent() возвратить 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;
}

это на самом деле не покупать вам много для вашего случая.

мое предложение: оберните весь шаблон в <div *ngIf="isDataAvailable"> (template content) </div>

и ngOnInit()

isDataAvailable:boolean = false;

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

хорошее решение, которое я нашел-это сделать на UI что-то вроде:

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

только когда: isDataLoaded верно отображается страница.


вы можете предварительная загрузка ваши данные с помощью распознавателей в Angular2+, распознаватели обрабатывают данные до полной загрузки компонента.

есть много случаев, когда вы хотите загрузить свой компонент только в том случае, если происходит определенная вещь, например, перейдите к панели мониторинга, только если человек уже вошел в систему, в этом случае решатели так удобны.

посмотрите на простую диаграмму, которую я создал для вас для одного из способов использования resolver для отправки данных в ваш компонент.

enter image description here

применение Сельсин чтобы ваш код был довольно простым, я создал фрагменты для вас, чтобы увидеть, как можно создать распознаватель:

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;
      });
  }
/////

и маршрут что-то вроде этого (обычно в приложение.маршрутизирующий.файл ТС):

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