【问题标题】:Map webservice data properly into typescript object (mapping Objects with capital letters / pascal case to camel case)将 web 服务数据正确映射到 typescript 对象(将大写字母/pascal 大小写的对象映射到驼峰大小写)
【发布时间】:2017-06-13 23:25:30
【问题描述】:

我在 Angular2 打字稿项目中发现了一件奇怪的事情。我有来自具有“级别”类型的网络服务的对象(它具有与来自网络服务的 Json 相同的属性)。在运行时,来自 web 服务的 Level 属性的开头有大写字母(Pascal 大小写),而我的 typescript 项目中的属性有小字母(在浏览器的开发人员调试工具中可见)。

我想我需要以某种方式将 json 属性映射到某个地方,而不是通过到处写“as Level[]”来进行强制转换。如何正确操作?

关于我应该发布一些代码的问题的更新:

(控制器)

ngOnInit(): void {
    this.levelsObservable = this.levelsService.getAllLevels();
            this.levelsObservable.subscribe(
              data => console.log(data)
        );
  }

(服务)

observable : Observable<Response>;
getAllLevels(): Observable<Level[]> {
    this.observable =  this.achievementsService.getAllAchievements(this.allLevelsUrlPart);
    return this.observable
    .map((response: Response) => {
      const srcData = response.json() as Level[];
      return srcData;})
    .catch(error => this.handleError(error));}

getAllAchievements(detailPath): Observable<Response> {
// prepare request url and header
this.specificUrl = this.webServiceUrl + detailPath;
this.headers.append('Content-type', 'application/json');
let options = new RequestOptions({ headers: this.headers });
this.result = this.http.get(this.specificUrl, options)
.catch(error => this.handleError(error));
return this.result;}

更新: 我在下面的一个答案的帮助下稍微完善了我的代码(上面没有集成,因为对于解决主要问题不是必需的)。 我尝试使用下面的其他答案来解决骆驼案例,但它不起作用(我有一个数组,数组中是具有属性的对象,但迭代器方法无法访问对象的属性)。

更新: 我终于成功了(!):) 我稍微缩短了这篇文章,现在将在下面发布我的解决方案。它肯定不是最漂亮的,但我很高兴在搜索了几个小时后得到了一个。感谢所有帮助我的人在这里的伟大和投入!

【问题讨论】:

  • 用我们无能为力的代码更新您的帖子
  • 您需要编写一个函数或方法,从 JSON 中获取原始对象并将其转换为 Level。请注意,SO 问题中应该有一个minimal reproducible example,而不仅仅是指向其他地方的整个代码库的链接。
  • 谢谢你,jonrsharpe。你能解释一下怎么做吗?那么我在哪里编写这个函数,我在哪里调用它最好呢?我会尝试做一个最小的例子

标签: json angular typescript mapping


【解决方案1】:

您可以使用它来获取小写的对象。

  modifiedSrc(srcData){
    let obj = {};
    Object.keys(srcData).forEach((key)=>{
      obj[key.uncapitalize()] = srcData[key];
    })
    return obj
  }
  String.prototype.uncapitalize = function() {
    return this.charAt(0).toLowerCase() + this.slice(1);
  }

然后就可以返回修改后的数据了

getAllLevels(): Observable<Level[]> {
    this.observable =  this.achievementsService.getAllAchievements(this.allLevelsUrlPart);
    return this.observable
    .map((response: Response) => {
      const srcData = response.json() as Level[];
      return this.modifiedSrc(srcData);})
    .catch(error => this.handleError(error));}

【讨论】:

  • 非常感谢。我现在明白了我必须把这些东西放在哪里,以及它是如何获得骆驼箱中的属性的。这种方法对我的用例来说有点太具体了,因为我可能只想在我的 typescript 对象上拥有一些 json 属性(例如 10 个中的 3 个)(当涉及其他成就时)。那我该如何映射属性呢?
  • 我不太了解你。你能用一个例子或更好地解释一下,添加一个新问题吗?
  • 我会尝试重新表述,因为我认为它过多地引用了原始问题来打开一个新问题:目前我们只是将 JSON 对象中的所有属性直接转换为一个完全正确的级别相同的属性(除了开头的驼峰字母)。如果我的 typescript 对象上的属性少于 JSON 中的属性,我该怎么办?例如。我在 JSON 上有 Id、Name、Number 并且希望名称和数字 only 在 Typescript 中处于某个级别?它会像这样工作还是我需要做任何其他事情,除了在 Level 类上声明名称和编号?
  • 这本身会。类型只存在于编译中,之后是纯 JS。并且 modifiedSrc 是在代码运行时创建的。打字稿没有办法理解它的类型。所以你可以使用相同的代码。或者,如果您只想要您提到的属性,我要求您查看lodashpick。希望对您有所帮助。
  • 感谢您的回答。如果可能的话,我不想只为此安装另一个框架。上面的代码对我不起作用。我需要将“obj”初始化为没有收到类型投诉的 Level[]。但是,我又得到了旧的属性。它无法工作,因为我有一个 Levels[] 列表,并且我需要 camelCase 中数组成员的每个属性。所以循环中的第一个键是 0(数组索引)。您需要在此处访问每个对象的属性的内部循环,但无法访问它们。所以还没有可行的解决方案:(
【解决方案2】:

你把这两种方法都复杂化了。把它简单化为

this.webServiceUrl = "http...." ;       // your service end point address
this.headers.append('Content-type', 'application/json');
let options = new RequestOptions({ headers: this.headers });

// For all your error handling 
private handleError(error: Response) {
        console.log(error);
        return Observable.throw(error.json().error || 'Internal Server error');
}   

您的服务方法可以使用 TypeCasting,看起来像

getAllLevels(detailPath): Observable<Level[]> {
    return this.http.get(detailPath, options)
                  .map((response: Response) => <Level[]>response.json())
                  .catch(this.handleError);
}

你的组件应该向你的服务提出请求

ngOnInit() : void{
        this._myService.getAllLevels()
                    .subscribe(levels => this.levels = levels,
                    error =>this.errorMessage =<any> error);

}  

你的变量声明必须是这样的

levels:Level[];

【讨论】:

  • 感谢您的回答和提示。我整合了它们。单独的类型转换并不能解决问题(不幸的是)。我认为这是因为大小写的不同。
  • 你的意思是 PascalCasecamelCase
【解决方案3】:

所以最后...我找到了解决方案!肯定不是最漂亮的,但很容易理解并通过努力和研究完成:

private useLevelProperties (response: any): Level[]{
    let levels: Level[] = [];
     Object.keys(response).forEach((key) => {
       //create a new object and just take out the json parts needed. The webservice retrieves Pascal case letters, so we 
       //need to convert them into camel case ones.
      this.level = new Level(response[key]["AchievementId"], response[key]["Image"],
        response[key]["GrantedTo"], response[key]["GrantedBy"], response[key]["GrantedWhen"],  response[key]["Description"], 
        response[key]["Name"], response[key]["CompetitionCode"], response[key]["Number"]);

      levels[key] = this.level;
  });

     return levels;
  };

【讨论】:

    【解决方案4】:

    另一种选择是在服务器端使用骆驼案例的额外 json 选项:example for server-side camel casing

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      • 2015-10-10
      • 2018-12-18
      • 1970-01-01
      • 2013-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多