如何在Angular 8中启动应用程序时首先完成数据加载工作

问题描述 投票:0回答:3

这是我的Angular应用。我的应用程序将从API(临时在JSON文件中)获取数据,并显示在许多其他同级组件中。因此,我决定创建一个用于获取并存储数据的category.service.ts。在我的应用程序启动时,我首先使用APP_INITIALIZER来运行此服务。但是存在一个问题:该服务首先运行,AppComponent在服务获取数据之前运行。所以我的视图没有数据。

如果我单击将按钮路由到该组件,则一切运行正常。但是,当我通过URL路径或F5(刷新页面)转到该组件时,什么也没有显示

category.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/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 { }
javascript angular typescript service
3个回答
1
投票

这是常见的情况-例如,您显示的页面尚不提供数据-例如在连接速度慢和连接不良的情况下,它甚至可以做更多的工作-连接断开并且未收到数据。

因此,您的页面应该不仅可以显示收到的数据,还可以显示另外两个状态:加载和错误。

(因此建议为“添加加载程序”。


1
投票

我建议使用Observable

喜欢您的分类服务

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

并且在您的组件中

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

0
投票

// data.service.ts

import { Injectable } from "@angular/core";
import { HttpClient, HttpClientModule } from "@angular/common/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.com/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.component";
import { AppComponent } from "./app.component";
import { DataService } from "./data.service";
import { HttpClientModule } from "@angular/common/http";
import {DetailComponent} from './detail/detail.component'

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


//list-data.component.ts

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

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

有替代方法可以解决此问题:

  • 一个是您可以使用加载程序,可以显示该加载程序,直到服务调用结束。

  • 第二,您可以使用* ngIf =“ categories?.length”,它将隐藏您的组件,直到您的服务调用结束。

我希望它能解决您的问题。

© www.soinside.com 2019 - 2024. All rights reserved.