【问题标题】:Angular 4, angular-in-memory-web-api, and Observables: createDb() returning Observable or Promise does not workAngular 4、angular-in-memory-web-api 和 Observables:createDb() 返回 Observable 或 Promise 不起作用
【发布时间】:2018-03-02 17:26:15
【问题描述】:

我已经解决这个问题几天了,无法继续前进。

我正在尝试使用一些表示具有外键关系的表的源 JSON 文件来模拟数据库。假设有一个实体A 和一个实体B,其中AB 具有多对一的关系。除了需要一些额外的清理之外,JSON 文件只列出了这些关系的主键,所以我有 DTO 包装器 RawARawB,一旦我得到数据,我可以分别映射到 AB

我正在使用 angular-in-memory-web-api,因此我已将 app.module.ts 设置为使用允许我检索 JSON 文件的自定义服务,如下所示:

HttpClientInMemoryWebApiModule.forRoot(
  InMemoryDataService,
  { apiBase: '/api', dataEncapsulation: false, passThruUnknownUrl: true }
)

在我的app.component.ts中,我暂时有一个ngOnInit()方法来测试这个数据库的构建:

ngOnInit() {
  let result = this.http.get('/api/A')
    .subscribe(
      next => { console.log('next:'); console.log(next); },
      error => { console.log('error:'); console.log(error); },
      () => console.log('complete')
    );
}

据我了解,内存数据库应该看到这个请求,在我的服务上调用 createDb(),并订阅我的方法返回的 Observable,然后使用我在 @ 中创建的 As 列表987654334@.

我无法让它工作。我尝试了很多东西,其中最直观的可能是:

// most imports omitted, but I am using
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';

@Injectable()
export class InMemoryDataService implements InMemoryDbService() {
  private static aUrl = './assets/data/a.json';
  private static bUrl = './assets/data/b.json';

  private http: HttpClient;

  constructor( private injector: Injector ) {}

  createDb( reqInfo?: RequestInfo ): {} | Observable<{}> | Promise<{}> {
    this.http = this.injector.get(HttpClient);

    return Observable.forkJoin(
        this.http.get<RawA[]>(InMemoryDataService.aUrl),
        this.http.get<RawB[]>(InMemoryDataService.bUrl)
      ).map(
        result => {
          let bs = (result[1] as RawB[]).map(raw => new B(raw));
          let as = (result[0] as RawA[]).map(raw => new A(raw, bs));
          return { A: as, B: bs };
        }
      );
  }
}

ngOnInit() 中的 subscribe() 回调永远不会运行。我尝试了映射、订阅、转换为 Promise 和发誓的各种组合,但我没有比 ngOnInit() 从未做任何事情或提示内存数据库返回 404 更好的方法了。

我知道forkJoin() 文档警告说,所有 Observable 都需要返回才能产生任何值,但据我所知,如果包装管道订阅了两个 http.get() 调用,则它们应该返回。以下代码成功记录了我期望的数据库(但它生成了 404,可能是因为立即调用 api/A 看到了一个空数组):

  createDb( reqInfo?: RequestInfo ): {} | Observable<{}> | Promise<{}> {
    this.http = this.injector.get(HttpClient);

    let database: { A: A[], B: B[] } = { A: [], B: [] };
    Observable.forkJoin(
        this.http.get<RawA[]>(InMemoryDataService.aUrl),
        this.http.get<RawB[]>(InMemoryDataService.bUrl)
      ).subscribe(
        result => {
          database.B = (result[1] as RawB[]).map(raw => new B(raw));
          database.A = (result[0] as RawA[]).map(raw => new A(raw, database.B));
          console.log(database);
          return database;
        }
      );
    return database;
  }
  // console logs {A: Array(100), B: Array(20)}, and inspection shows the field values are all correct

我缺少什么来完成这项工作?另外,这真的很棘手,还是我遗漏了一些明显的东西?

【问题讨论】:

    标签: angular rxjs observable in-memory-database


    【解决方案1】:

    创建数据库

    查看您的代码:

    Observable.forkJoin(
        this.http.get<RawA[]>(InMemoryDataService.aUrl),
        this.http.get<RawB[]>(InMemoryDataService.bUrl)
      ).subscribe(
    

    我怀疑由于您连接了所有 http 请求并且尚未创建 Db,因此这些请求将始终处于等待状态。

    为了克服它,我会使用其他东西来获取 json 数据。

    例如Fetch API:

    createDb( reqInfo?: RequestInfo ): Observable<{}> | Promise<{}> {
      this.http = this.injector.get(HttpClient);
    
      return Promise.all([
          fetch(InMemoryDataService.aUrl),
          fetch(InMemoryDataService.bUrl)
        ])
        .then((result: any) => {
          return Promise.all(result.map(x => x.json()));
        })
        .then(
          result => {
            const bs = (result[1] as RawB[]).map(raw => new B(raw));
            const as = (result[0] as RawA[]).map(raw => new A(raw, bs));
            return { A: as, B: bs };
          }
        );
    }
    

    ApiBase

    您需要更改的另一件事是 api url

    app.module.ts

    { apiBase: 'api/', dataEncapsulation: false, passThruUnknownUrl: true }
               ^^^^^^
    

    component.ts

    let result = this.http.get('api/A')
                               ^^^^^^^^^
    

    或者您可以使用以下一对:

    { apiBase: '/', dataEncapsulation: false, passThruUnknownUrl: true }
    
    let result = this.http.get('/A')
    

    原因是angular-in-web-memory-apiparses your url

    【讨论】:

    • 稍微重写您的 createdDb() 方法并删除 URL 中不正确的斜线效果很好。非常感谢! +1,以及 SO 让我奖励它时的赏金。
    猜你喜欢
    • 2017-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-27
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多