Pertanyaan Angular2: Bagaimana cara memuat data sebelum merender komponen?


Saya mencoba memuat peristiwa dari API saya sebelum komponen dirender. Saat ini saya menggunakan layanan API yang saya sebut dari fungsi ngOnInit dari komponen.

Saya EventRegister komponen:

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

Saya EventRegister template

<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>

Layanan API saya

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

Komponen akan diberikan sebelum panggilan API di ngOnInit fungsi selesai mengambil data. Jadi saya tidak pernah melihat id acara di template tampilan saya. Jadi sepertinya ini adalah masalah ASYNC. Saya mengharapkan pengikatan ev (EventRegister komponen) untuk melakukan beberapa pekerjaan setelah ev properti ditetapkan. Sayangnya itu tidak menunjukkan div ditandai dengan *ngIf="ev" ketika properti diatur.

Pertanyaan: Apakah saya menggunakan pendekatan yang baik? Jika tidak; Apa cara terbaik untuk memuat data sebelum komponen mulai dirender?

CATATAN: Itu ngOnInit pendekatan digunakan dalam hal ini tutorial angular2.

EDIT:

Dua solusi yang memungkinkan. Pertama adalah membuang parit fetchEvent dan cukup gunakan layanan API di ngOnInit fungsi.

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

Solusi kedua. Seperti jawaban yang diberikan.

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

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

76
2018-02-26 15:17


asal


Jawaban:


memperbarui

asli

Kapan console.log(this.ev) dieksekusi setelah this.fetchEvent();, ini tidak berarti fetchEvent() panggilan dilakukan, ini hanya berarti bahwa itu dijadwalkan. Kapan console.log(this.ev) dijalankan, panggilan ke server bahkan tidak dibuat dan tentu saja belum mengembalikan nilai.

Perubahan fetchEvent() untuk mengembalikan a 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
    });
 }

perubahan ngOnInit() untuk menunggu Promise untuk menyelesaikan

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

Ini sebenarnya tidak akan membeli banyak untuk kasus penggunaan Anda.

Saran saya: Bungkus seluruh template Anda dalam sebuah <div *ngIf="isDataAvailable"> (template content) </div>

dan masuk ngOnInit()

isDataAvailable:boolean = false;

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

82
2018-02-26 15:22



Solusi bagus yang saya temukan adalah melakukan sesuatu pada UI seperti:

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

Hanya ketika: isDataLoaded benar halaman dirender.


24
2017-07-26 09:31



Kamu bisa pra-ambil data Anda dengan menggunakan Resolvers in Angular2 +, Resolvers memproses data Anda sebelum Komponen Anda dimuat sepenuhnya.

Ada banyak kasus yang Anda ingin memuat komponen Anda hanya jika ada hal tertentu terjadi, misalnya menavigasi ke Dashboard hanya jika orang tersebut sudah masuk, dalam hal ini Resolver sangat berguna.

Lihatlah diagram sederhana yang saya buat untuk Anda untuk salah satu cara Anda dapat menggunakan resolver untuk mengirim data ke komponen Anda.

enter image description here

Menerapkan Resolver untuk kode Anda cukup sederhana, saya membuat cuplikan untuk Anda untuk melihat bagaimana Resolver dapat dibuat:

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

dan di modul:

import { MyResolver } from './my-resolver.service';

@NgModule({
  imports: [
    RouterModule.forChild(myRoutes)
  ],
  exports: [
    RouterModule
  ],
  providers: [
    MyResolver
  ]
})
export class MyModule { }

dan Anda dapat mengaksesnya di Anda Komponen seperti ini:

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

Dan di dalam Rute sesuatu seperti ini (biasanya di file app.routing.ts):

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

21
2018-06-08 14:00