[typescript] Angular2 : 구성 요소를 렌더링하기 전에 데이터를로드하는 방법은 무엇입니까?

구성 요소가 렌더링되기 전에 API에서 이벤트를로드하려고합니다. 현재 구성 요소의 ngOnInit 함수에서 호출하는 API 서비스를 사용하고 있습니다.

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

ngOnInit함수 에서 API 호출 이 데이터 반입을 완료 하기 전에 구성 요소가 렌더링됩니다 . 따라서 뷰 템플릿에서 이벤트 ID를 볼 수 없습니다. 이것이 ASYNC 문제인 것 같습니다. 속성이 설정된 후에 ev( EventRegister구성 요소) 의 바인딩 이 약간의 작업을 수행 할 것으로 예상했습니다 ev. 슬프게도 속성이 설정 될 때로 div표시 되지 않습니다 *ngIf="ev".

질문 : 좋은 접근 방식을 사용하고 있습니까? 그렇지 않다면; 구성 요소가 렌더링되기 전에 데이터를로드하는 가장 좋은 방법은 무엇입니까?

참고 :ngOnInit방법은이 angular2 튜토리얼 에서 사용됩니다 .

편집하다:

두 가지 가능한 솔루션. 먼저을 버리고 함수 fetchEvent에서 API 서비스를 사용하십시오 ngOnInit.

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



답변

최신 정보

실물

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가 true 인 경우에만 페이지가 렌더링됩니다.


답변

Angular2 +의 리졸버를 사용하여 데이터를 프리 페치 할 수 있습니다. 리졸버는 컴포넌트가 완전히로드되기 전에 데이터를 처리합니다.

특정 상황이 발생하는 경우에만 구성 요소를로드하려는 경우가 많습니다. 예를 들어 이미 로그인 한 사람 만 대시 보드로 이동하는 경우에는이 경우 해결 프로그램이 매우 편리합니다.

리졸버를 사용하여 데이터를 컴포넌트로 보낼 수있는 방법 중 하나를 위해 내가 작성한 간단한 다이어그램을 살펴보십시오.

여기에 이미지 설명을 입력하십시오

코드에 리졸버 를 적용하는 것은 매우 간단합니다. 리졸버를 만드는 방법을 알 수 있도록 스 니펫을 만들었습니다.

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

그리고 Route에서 다음과 같이 (보통 app.routing.ts 파일에서) :

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


답변