Angular2: घटक रेंडर करने से पहले डेटा को कैसे लोड करना है?


143

घटक रेंडर होने से पहले मैं अपने 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>

मेरी एपीआई सेवा

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 कॉल करने से पहले घटक प्रदान किया जाता है। इसलिए मुझे अपने व्यू टेम्प्लेट में ईवेंट आईडी देखने को कभी नहीं मिला। तो ऐसा लगता है कि यह एक ASYNC समस्या है। मुझे उम्मीद थी कि संपत्ति के सेट होने के बाद ev( EventRegisterकुछ) काम करने के लिए ( घटक) की बाध्यता होगी ev। दुर्भाग्य से यह प्रदर्शित नहीं करता है divके साथ चिह्नित *ngIf="ev"जब गुण सेट हो जाता है।

प्रश्न: क्या मैं एक अच्छे दृष्टिकोण का उपयोग कर रहा हूँ? अगर नहीं; घटक को रेंडर करने से पहले डेटा लोड करने का सबसे अच्छा तरीका क्या है?

नोट:ngOnInit दृष्टिकोण इस में प्रयोग किया जाता है angular2 ट्यूटोरियल

संपादित करें:

दो संभव उपाय। पहले समारोह fetchEventमें खाई और बस एपीआई सेवा का उपयोग 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);
}

जवाबों:


127

अपडेट करें

मूल

जब 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;
}

3
दरअसल, आपकी पहली टिप्पणी ने खूबसूरती से काम किया। मैंने केवल पूरे fetchEventफ़ंक्शन को हटा दिया और केवल apiService.get.eventफ़ंक्शन को अंदर रखा ngOnInitऔर जैसा कि मैंने इरादा किया था, यह काम किया। धन्यवाद! जैसे ही यह मुझे अनुमति देता है मैं आपको उत्तर स्वीकार कर लूंगा।
टॉम ऑल्बर्स

किसी कारण से, मैंने एंगुलर 1.x पर इस दृष्टिकोण का उपयोग किया। IMHO, यह एक उचित समाधान के बजाय एक हैक के रूप में लिया जाना चाहिए। हमें कोणीय 5 में बेहतर करना चाहिए
हवामहल

वास्तव में आपको क्या पसंद नहीं है? मुझे लगता है कि दोनों दृष्टिकोण पूरी तरह से ठीक हैं।
गुंटर ज़ोचबॉयर

54

एक अच्छा समाधान जो मुझे मिला है वह कुछ यूआई पर करना है जैसे:

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

केवल जब: isDataLoaded सच है पृष्ठ रेंडर किया गया है।


3
मुझे लगता है कि यह समाधान केवल कोणीय 1 के लिए है न कि कोणीय> = 2 के लिए क्योंकि कोणीय के यूनिडायरेक्शनल डेटा फ़्लो नियम ने इसे देखने के बाद अपडेट को देखने से मना कर दिया है। घटक के दृष्टिकोण की रचना के बाद ये दोनों हुक आग लगाते हैं।
zt1983811

1
Div सब पर व्याप्त नहीं है। हम इसे प्रदान करने से रोकने का इरादा नहीं करते हैं, हम इसमें देरी करना चाहते हैं। इसका कारण यह नहीं है क्योंकि कोणीय 2 में कोई दो तरह से बंधन नहीं है। @ एफिल आपको समझा सकता है कि यह आपके लिए कैसे काम करता है?
ishandutta2007

1
ठीक है मैं उपयोग कर रहा था ChangeDetectionStrategy.Push, इसे बदलने के लिए ChangeDetectionStrategy.Defaultइसे दो तरह से टेम्पलेट के साथ बाँधा गया।
ishandutta2007

कोणीय 6. काम करता है।
TDP

क्या एक अद्भुत हैक कोणीय 2x में काम करता है।
निशील भावे

48

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

और रूट में कुछ इस तरह (आमतौर पर app.rout.ts फ़ाइल में):

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

1
मुझे लगता है कि आप Routesसरणी के तहत मार्ग विन्यास प्रविष्टि (आमतौर पर app.rout.ts फ़ाइल में) से चूक गए :{path: 'yourpath/:id', component: YourComponent, resolve: { myData: MyData}}
Voicu

1
@ वीको, यह सभी भागों को कवर करने के लिए नहीं है, लेकिन मैं इससे सहमत हूं, यह उत्तर को अधिक व्यापक बनाता है, इसलिए मैंने जोड़ा ... धन्यवाद
Alireza

5
बस अंतिम भाग को सही करने के लिए, मार्ग में रिज़ॉल्यूशन पैरामीटर को रिसोल्वर को इंगित करने की आवश्यकता होती है, न कि डेटा प्रकार, अर्थातresolve: { myData: MyResolver }
क्रिस हैन्स

क्या MyData एक मॉडल ऑब्जेक्ट है जो MyService में परिभाषित होता है?
Isuru Madusanka

1
यह समाधान पृष्ठ लोड होने से पहले डेटा प्राप्त करने के लिए अच्छा है, लेकिन लॉग इन किए गए उपयोगकर्ता और न ही उपयोगकर्ता भूमिकाओं के लिए। इसके लिए आपको
एंजल क्यू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.