Angular-in-memory-web-api 中的多个集合

Posted

技术标签:

【中文标题】Angular-in-memory-web-api 中的多个集合【英文标题】:Multiple collections in Angular-in-memory-web-api 【发布时间】:2017-03-02 00:05:44 【问题描述】:

我们如何使用 Angular-in-memory-web-api 创建多个集合? 单一收藏不是问题。但我无法为多个集合实现它。

例如,我想在内存数据库中创建两个集合——国家和城市。任何想法,如何做到这一点?

【问题讨论】:

【参考方案1】:

只需返回一个包含两个数组的对象。在 Angular 的示例中,您会看到类似

createDb() 
  let heroes = [ .. ]
  return  heroes 

如果您还不知道这一点, heroes 只是写作 heroes: heroes 的简写。因此,如果您有两个集合,则只需将其添加为另一个属性

createDb() 
  let heroes = [ .. ];
  let crises = [ .. ];
  return  heroes, crises ;
  // or  heroes: heroes, crises: crises 

返回的属性名称将用于 URL 中的路径。所以你可以使用

/api/heroes/1
/api/crises/1

【讨论】:

这很好 - 但 heroes example 也会覆盖 genId(heroes: Hero[]): number ... 。现在我尝试重载它以使用crises(即genId(crises: Crises[]): number ... ),但到目前为止没有运气(“重复函数实现”)。你会怎么做? (在示例中,它返回最大 id + 1 以便能够添加新项目) 终于找到了让它工作的方法,并将其发布在here 作为您答案的附加信息。【参考方案2】:

Paul's answer 中描述的方法是正确的,但是我错过了一个我想补充的细节:你如何正确指定 genId,所以它适用于两个集合?

答案是指用TypeScript(javascript 的超集)编写的“英雄”示例,特别是HTTP chapter。 在那里,通过实现模拟了一个表heroes

export class InMemoryDataService implements InMemoryDbService 
  createDb() 
    const heroes = [
       id: 11, name: 'Mr. Nice' ,
       id: 12, name: 'Narco' ,
      // ...
       id: 20, name: 'Tornado' 
    ];
    return heroes;
  

  // Overrides the genId method to ensure that a hero always has an id.
  // If the heroes array is empty,
  // the method below returns the initial number (11).
  // if the heroes array is not empty, the method below returns the highest
  // hero id + 1.
  genId(heroes: Hero[]): number 
    return heroes.length > 0 ? Math.max(...heroes.map(hero => hero.id)) + 1 : 11;
  

现在,如果您添加 第二个集合crises,如他的回答所示,即:

createDb() 
  let heroes = [  ... , ... ];
  let crises = [  ... , ... ];
  return  heroes, crises ;
  // or  heroes: heroes, crises: crises 

您如何为这两个集合提供genId(假设它们的类型为HeroCrises)?重载,就像您在 C# 中所做的那样,在 TypeScript 中不起作用,它会引发错误(“重复函数实现”)。


解决方案: 我发现,您可以使用 TypeScript's Generics 解决此问题,如下所示。将原来的genId 函数替换为以下通用版本:

genId<T extends Hero | Crises>(myTable: T[]): number 
  return myTable.length > 0 ? Math.max(...myTable.map(t => t.id)) + 1 : 11;

这里重要的是&lt;T extends Hero | Crises&gt;部分:这意味着T类型可以是HeroCrises:所以如果传递的参数是Hero[]或@987654344类型,它将被调用@。

有了这些知识,添加 3rd、4th、... 类很简单: 只需附加类即可。假设我们要添加类SuperHero,然后您只需通过| SuperHero 附加它,所以它看起来像:

genId<T extends Hero | Crises | SuperHero>(myTable: T[]): number 
  return myTable.length > 0 ? Math.max(...myTable.map(t => t.id)) + 1 : 11;

注意:作为先决条件,所有类HeroCrisesSuperHero)都需要声明一个数字 id 属性。


有用的链接:

HTTP chapter of Angular Tutorial

In-Memory-Web-API: Custom genId

Can You Specify Multiple Type Constraints For TypeScript Generics?

【讨论】:

@Matt,很高兴您提供了文档/相关文章的链接?【参考方案3】:

除了这个讨论之外,我不得不使用 Partial,因为它一直说我在完成英雄之旅第 6 课时缺少一个 id。我使用消息服务查看代码在停止工作之前走了多远,所以您可以忽略 this.log 行,但您可以将它们添加到您自己的项目中以帮助调试。首先,我将 addHero 更新如下:

addHero(hero: string): void this.log(`In addHero of HeroesComponent, name is: $hero`);
if (!hero)

  this.log(`In if(!hero.name) of add hero: $hero`);
  return;


this.heroService.addHero( name: hero  as Partial<Hero>)
  .subscribe(hero => 
    this.heroes.push(hero);
  );

然后我更新了 heros.service.ts 文件以使用部分 hero 并允许代码从 in-memory-data.service.ts 生成自己的 id:

addHero(hero: Partial): Observable this.log(`In addHero: heroeName is: $hero.name`); return this.http.post(this.heroesUrl, hero, this.httpOptions).pipe( tap((newHero: Hero) => this.log(`added hero with string id=$newHero.id`)), catchError(this.handleError("Error in addHero")));

据我所知,它现在按预期工作。可能还有更多代码需要更新,但这应该可以帮助任何出现以下错误消息的人:

ERROR in src/app/heroes/heroes.component.ts:52:30 - error TS2352: Conversion of type ' name: never; ' to type 'Hero' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Property 'id' is missing in type ' name: never; ' but required in type 'Hero'.

【讨论】:

以上是关于Angular-in-memory-web-api 中的多个集合的主要内容,如果未能解决你的问题,请参考以下文章

Angular - 如何将 ngFor 过滤到特定的对象属性数据

Angularjs2-zone.js:1382 GET http://localhost:3000/traceur 404 (Not Found)