Açısal2: Bileşeni oluşturmadan önce veri nasıl yüklenir?


143

Bileşen işlenmeden önce API'mdan bir olay yüklemeye çalışıyorum. Şu anda bileşen ngOnInit işlevinden çağrı API hizmetini kullanıyorum.

Benim EventRegisterbileşen:

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

Benim EventRegisterşablon

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

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

Bileşen, ngOnInitişlevdeki API çağrısı veriler getirilmeden önce oluşturulur . Bu yüzden görünüm şablonumda etkinlik kimliğini hiçbir zaman göremiyorum. Yani bu bir ASYNC problemi gibi görünüyor. Özellik ayarlandıktan sonra ev( EventRegisterbileşen) bağlama bazı işler yapmak bekleniyor ev. Ne yazık ki özellik ayarlandığında divile işaretli göstermez *ngIf="ev".

Soru: İyi bir yaklaşım mı kullanıyorum? Değilse; Bileşen oluşturulmaya başlamadan önce veri yüklemenin en iyi yolu nedir?

NOT:ngOnInit yaklaşım bu kullanılan angular2 öğretici .

DÜZENLE:

İki olası çözüm. Birincisi, işlevde fetchEventAPI hizmetini bırakmak ve kullanmaktı ngOnInit.

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

İkinci çözüm. Verilen cevap gibi.

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

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

Yanıtlar:


127

Güncelleme

orijinal

Sonra console.log(this.ev)yürütüldüğünde this.fetchEvent();, bu fetchEvent()çağrının yapıldığı anlamına gelmez , bu sadece programlandığı anlamına gelir. Ne zamanconsole.log(this.ev) yürütüldüğünde, sunucuya çağrı bile yapılmış değildir ve tabii ki henüz bir değer döndürmez etmiştir.

fetchEvent()Geri dönmek için değiştirinPromise

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

tamamlanmasını ngOnInit()beklemek için değiştirinPromise

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

Bu aslında kullanım durumunuz için çok fazla satın almaz.

Benim önerim: Tüm şablonunuzu bir <div *ngIf="isDataAvailable"> (template content) </div>

ve ngOnInit()

isDataAvailable:boolean = false;

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

3
Aslında, ilk yorumunuz güzel çalıştı. Ben sadece tüm kaldırıldı fetchEventfonksiyonu ve sadece koymak apiService.get.eventfonksiyonu ngOnInitve ben intendend olarak işe yaradı. Teşekkürler! Bana da izin verir vermez cevabını kabul edeceğim.
Tom Aalbers

Nedense, bu yaklaşımı Açısal 1.x üzerinde kullandım. IMHO, bu doğru bir çözüm yerine bir hack olarak alınmalıdır. Açısal 5'te daha iyisini yapmalıyız.
windmaomao

Bu konuda tam olarak neyi sevmiyorsunuz? Bence her iki yaklaşım da gayet iyi.
Günter Zöchbauer

54

Bulduğum güzel bir çözüm, kullanıcı arayüzünde şöyle bir şey yapmaktır:

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

Yalnızca: isDataLoaded true olduğunda sayfa işlenir.


3
Bu çözümün yalnızca Açısal 1 için değil Açısal> = 2 olduğunu düşünüyorum çünkü Açısal'ın tek yönlü veri akışı kuralı oluşturulduktan sonra görünümdeki güncellemeleri yasaklıyor. Bu kancaların her ikisi de, bileşenin görüşü oluşturulduktan sonra ateşlenir.
zt1983811

1
Div hiç alınmaz. Oluşturulmasını durdurmak istemiyoruz, geciktirmek istiyoruz. Çalışmamasının nedeni, açısal2'de iki yönlü bağlanma olmamasıdır. @phil sizin için nasıl çalıştığını açıklayabilir misiniz?
ishandutta2007

1
Tamam ben kullanıyordum ChangeDetectionStrategy.Pushdeğiştirmeyi, ChangeDetectionStrategy.Defaultmarka şablonla binded iki yolu.
ishandutta2007

açısal 6. Çalışır.
TDP

Ne harika bir kesmek açısal 2x çalışır.
nishil bhave

48

Sen edebilirsiniz ön getirme içinde resolverler kullanarak verilerinizi Angular2 + sizin Bileşen tamamen yüklenecek önce, çözücülere verilerinizi işlemek.

Bileşeninizi yalnızca belirli bir şey olduğunda yüklemek istediğiniz birçok durum vardır, örneğin Gösterge Tablosuna yalnızca önceden oturum açmış kişi varsa, bu durumda Çözümleyiciler çok kullanışlıdır.

Verileri bileşeninize göndermek için çözümleyiciyi kullanabileceğiniz yollardan biri için sizin için oluşturduğum basit şemaya bakın.

resim açıklamasını buraya girin

Uygulama Çözücü Kodunuza oldukça basittir, sana Çözümleyici oluşturulabilir nasıl görmek için parçacıkları oluşturdu:

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

ve modülde :

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

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

ve Bileşeninizden şu şekilde erişebilirsiniz :

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

Ve de Rota (genellikle app.routing.ts dosyasında) böyle bir şey:

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

1
Sanırım Routesdizinin altındaki rota yapılandırma girişini kaçırdınız (genellikle app.routing.ts dosyasında):{path: 'yourpath/:id', component: YourComponent, resolve: { myData: MyData}}
Voicu

1
@Voicu, tüm parçaları kapsaması gerekiyordu, ama katılıyorum, cevabı daha kapsamlı hale getiriyor, bu yüzden ekledim ... Teşekkürler
Alireza

5
Sadece son kısmı düzeltmek için, rotadaki resol parametresinin veri tipini değil, çözümleyicinin kendisini göstermesi gerekir, yaniresolve: { myData: MyResolver }
Chris Haines

Bu MyData, MyService içinde tanımlanan bir model nesnesi mi?
Isuru Madusanka

1
bu çözüm, sayfa yüklenmeden önce veri almak için iyidir, ancak günlüğe kaydedilen kullanıcıyı veya kullanıcı rollerini denetlemez. Bunun için Muhafızları kullanmalısınız
Angel Q
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.