17

I have a question about the Angular 5 httpClient.

This is a model class with a method foo() I'd like to receive from the server

export class MyClass implements Deserializable{
  id: number;
  title: string;

  deserialize(input: any) {
    Object.assign(this, input);
    return this;
  }

  foo(): string {
    // return "some string conversion" with this.title
  }
}

This is my service requesting it:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { MyClass } from './MyClass';

@Injectable({
  providedIn: 'root',
})
export class MyClassService {

  constructor(private http: HttpClient) {
  }

  getMyStuff(): Observable<MyClass[]> {
    // this is where I hope to convert the json to instances of MyClass
    return this.http.get<MyClass[]>('api/stuff')
  }
}

My Problem

When I ask the service for instances of MyClass I get the data, but I cannot run {{ item.foo() }} in the template. Also, when I console.log() the typeof of an item where it is received in the service, I do no see instances of an object of MyClass.

What am I doing wrong? I thought that writing this.http.get<MyClass[]>('api/stuff') would do the conversion.

Any hints? Thank you in advance!

Guerric P
  • 30,447
  • 6
  • 48
  • 86
Colja
  • 209
  • 1
  • 3
  • 11
  • Have a read of this to understand how to use Deserializable in your model with data from an API. https://nehalist.io/working-with-models-in-angular/ – S. Dev May 27 '18 at 11:36
  • Similar question to https://stackoverflow.com/questions/47499324/angular-5-models-httpclient-type-casting – toxaq Jan 11 '19 at 06:49
  • similar question here https://stackoverflow.com/questions/63964124/angular-convert-api-data-into-new-data-type-in-reusable-clean-method –  Sep 20 '20 at 09:21

2 Answers2

33

When doing that, TypeScript only does "type assertion". It means that you're telling TypeScript that your object is of type MyClass, but the object isn't actually an instance of MyClass at runtime. In order to call functions defined in your model object, you have to define constructors in your model classes like that :

constructor(obj?: any) {
    Object.assign(this, obj);
}

Then in your services add a mapping like this :

http.get<MyClass>('/my-class').pipe(
      map(res => new MyClass(res))

Note: the code above is RxJS 6 style, i don't know which version you are using

Guerric P
  • 30,447
  • 6
  • 48
  • 86
  • Thanks to you I reread [this tutorial](https://nehalist.io/working-with-models-in-angular/) that I did not do to the end. What I now do in the service is this: `return stuffObjects.map(stuff => new MyClass().deserialize(stuff)); – Colja May 27 '18 at 12:24
  • 2
    You're welcome, I personnally like the constructor way, the `Deserialize` interface is another suitable option – Guerric P May 27 '18 at 13:01
  • 2
    this will only work when `MyClass` does not have complex members (eg members of type `Date` or other classes) – Jota.Toledo Oct 04 '18 at 16:05
  • 3
    @Jota.Toledo yes, and this can be solved by defining setters for those properties – Guerric P Oct 04 '18 at 17:05
  • 1
    thanks very helpful https://stackoverflow.com/questions/36014161/angular2-http-get-cast-response-into-full-object –  Sep 20 '20 at 09:22
-2

It works for me like this

import { HttpClient } from '@angular/common/http';

...
this.httpClient.get<MyResponse>('http://......').toPromise()
      .then((myResponse) => {
        console.log('myResponse.myField: ' + JSON.stringify(tokenResponse));
      })
      .catch((error) => {
        console.log('Promise rejected with ' + JSON.stringify(error));
      });

...
interface MyResponse {
  myField: string;
  myOtherField: string;
}
interrupt
  • 2,030
  • 17
  • 14
  • Please add some explanation to your answer such that others can learn from it – Nico Haase May 28 '20 at 07:03
  • Please read the question again, it's about calling functions on a business class hydrated from the backend, how an interface solves this problem? – Guerric P May 29 '20 at 14:22
  • @GuerricP this question is about deserializing server response into a model and this is exactly what my code does. – interrupt Feb 07 '21 at 17:38