javascript - How to load data service done first when app starting in Angular 8 - Stack Overflow

This is my Angular App. My app will get data from API (temporarily in JSON file) and show in many anoth

This is my Angular App. My app will get data from API (temporarily in JSON file) and show in many another sibling ponent. So I decide to create a category.service.ts that I get and store data in. I using APP_INITIALIZER to run this service first when my app started. But there is a problem that: This service is running first, AppComponent runs before service get data done. So my view have empty of data.

If I click button routing to this ponent, everything run perfect. But when I go to this ponent by url path or F5(refresh page), nothing is shown

category.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/mon/http';
@Injectable({
  providedIn: 'root'
})
export class CategoryService {
  DATA_CATEGORIES = 'assets/categories.json';
  private _categories = [];
  constructor(private http: HttpClient) {
  }
  get categories() {
    return this._categories;
  }
  Init(): Promise<any> {
    return new Promise<void>(resolve => {
      this.http.get(this.DATA_CATEGORIES).subscribe(data => {
        this._categories = Array.from(Object.keys(data), k => data[k]);
        console.log("load data...");

      });
      resolve();
    });
  }
}

This is my Angular App. My app will get data from API (temporarily in JSON file) and show in many another sibling ponent. So I decide to create a category.service.ts that I get and store data in. I using APP_INITIALIZER to run this service first when my app started. But there is a problem that: This service is running first, AppComponent runs before service get data done. So my view have empty of data.

If I click button routing to this ponent, everything run perfect. But when I go to this ponent by url path or F5(refresh page), nothing is shown

category.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/mon/http';
@Injectable({
  providedIn: 'root'
})
export class CategoryService {
  DATA_CATEGORIES = 'assets/categories.json';
  private _categories = [];
  constructor(private http: HttpClient) {
  }
  get categories() {
    return this._categories;
  }
  Init(): Promise<any> {
    return new Promise<void>(resolve => {
      this.http.get(this.DATA_CATEGORIES).subscribe(data => {
        this._categories = Array.from(Object.keys(data), k => data[k]);
        console.log("load data...");

      });
      resolve();
    });
  }
}

app.module.ts

export function initializeCategoryService(catService: CategoryService) {
  return (): Promise<any> => {
    return catService.Init();
  }
}
@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    StoriesFilterPipe,
    ViewStoryComponent,
    ViewCatComponent,
    FrontEndComponent,
    SearchComponent,
    BackEndComponent,
    CrudStoryFormComponent,
    CrudStoryComponent,
    JwPaginationComponent,
    CrudCatComponent,
    CrudCatFormComponent,
    CrudCatSearchResultComponent,
    CatListComponent

  ],
  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule,
    HttpClientModule,
  ],
  providers: [
    StoryService,
    CategoryService,
    {
      provide: APP_INITIALIZER, useFactory: initializeCategoryService, deps: [CategoryService], multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Share Improve this question edited Feb 10, 2020 at 10:21 Nguyen Duc Binh asked Feb 10, 2020 at 9:09 Nguyen Duc BinhNguyen Duc Binh 131 gold badge1 silver badge4 bronze badges 1
  • try to use *ngIf in your app.ponent.html until your data is loaded – chana Commented Feb 10, 2020 at 9:17
Add a ment  | 

3 Answers 3

Reset to default 2

What I will suggest is to use Observable

like in your category service

import { Observable, Subject } from 'rxjs';
export class CategoryService {
    private loadDataSub = new Subject<any>();
    loadDataObservable$ = this.loadDataSub.asObservable();

    emitLoadDataSuccess() {
        this.loadDataSub.next();
    }

Init(): Promise<any> {
    return new Promise<void>(resolve => {
      this.http.get(this.DATA_CATEGORIES).subscribe(data => {
        this._categories = Array.from(Object.keys(data), k => data[k]);
        console.log("load data...");
        this.emitLoadDataSuccess(); // here we are emitting event
      });
      resolve();
    });
 }
}

And In your ponent

export class AppComponent implements OnInit {
    constructor(private categoryService: CategoryService) {
          this.categoryService.loadDataObservable$.subscribe(() => {
              // here you can get data, this will only trigger when data is loaded from API
          });
    }
}

This is mon case - i.e. you shows page while data is not avaliable yet - at slow and bad connections for instance, and it can do even more - connection was broken and data was nto recieved.

So, your page should be able to show not only data recieved, but also two another states: loading and error.

(So the advise is "add loader").

// data.service.ts

import { Injectable } from "@angular/core";
import { HttpClient, HttpClientModule } from "@angular/mon/http";

@Injectable()
export class DataService {
  private _categories = [];

  constructor(private http: HttpClient) {}
  get categories() {
    return this._categories;
  }
  getData(): Promise<any[]> {
    return new Promise<any[]>(resolve => {
      this.http.get('https://api.myjson./bins/18qku4').subscribe(data => {
        this._categories = Array.from(Object.keys(data), k => data[k]);
        console.log("load data...");
        resolve(this._categories);
      });
    });
  }
}


// app.module.ts

import { NgModule, APP_INITIALIZER } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms";
import { RouterModule } from "@angular/router";
import { ListDataComponent } from "./list-data/list-data.ponent";
import { AppComponent } from "./app.ponent";
import { DataService } from "./data.service";
import { HttpClientModule } from "@angular/mon/http";
import {DetailComponent} from './detail/detail.ponent'

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule,
    RouterModule.forRoot([
      { path: "", ponent: ListDataComponent },
      { path: "detail", ponent: DetailComponent }
    ])
  ],
  declarations: [AppComponent, ListDataComponent,DetailComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}


//list-data.ponent.ts

import { Component, OnInit } from "@angular/core";
import { DataService } from "../data.service";

@Component({
  selector: "app-list-data",
  templateUrl: "./list-data.ponent.html",
  styleUrls: ["./list-data.ponent.css"],
  providers: [DataService],
})
export class ListDataComponent implements OnInit {
  categories = [];
  constructor(service: DataService) {
    service.getData().then(data => {
      debugger;
      this.categories = data;
    });
  }
  ngOnInit() {}
}

There are alternatives to resolve this issue:

  • One is you can use a loader which you can display until the service call finishes.

  • Second is you can use *ngIf="categories?.length" which will keep your ponent hides until your service call finishes.

I hope it will resolve your issue.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744920375a4601095.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信