Angular 4,angular-in-memory-web-api和Observables:createDb()返回Observable或Promise不起作用

问题描述 投票:1回答:1

我一直在打击这个问题几天,不能继续前进。

我试图使用一些代表具有外键关系的表的源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,然后使用我在A中创建的subscribe()s列表。

我不能让这个工作。我尝试了很多东西,也许最直观的是:

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

subscribe()ngOnInit()回调从未运行过。我已经尝试了映射,订阅,转换为Promises和发誓的各种组合,我不能比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个回答
1
投票

CREATEDB

看看你的代码:

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-api parses your url

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