Transforming httpClient responses into structured model objects in Angular 6

I am seeking guidance on the usage of Angular 5 httpClient.

This particular model class contains a method called foo() that I wish to retrieve 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
  }
}

Below is my service code 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')
  }
}

The Issue at Hand

Upon requesting instances of MyClass from the service, although data is received, I am unable to execute {{ item.foo() }} in the template. Furthermore, when examining the output of console.log(), the typeof an item does not seem to represent objects of MyClass.

What mistake have I committed? I initially believed that using

this.http.get<MyClass[]>('api/stuff')
would handle the conversion process.

Any advice or suggestions would be greatly appreciated! Thank you!

Answer №1

When working with TypeScript, using "type assertion" is key. This means explicitly stating to TypeScript that your object conforms to a specific type, such as MyClass. However, it's important to note that this does not change the actual type of the object at runtime. To be able to utilize functions defined within your model object, constructors must be defined in your model classes like so :

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

In your services, include a mapping similar to the following example:

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

Please keep in mind that the code snippet above follows the RxJS 6 style - it would be advisable to confirm if this version aligns with the one you are utilizing.

Answer №2

Here is the solution that worked for me:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Update to the latest version of typescript, implemented a read-only array

After updating my project from Typescript 3.5 to 3.8, everything was running smoothly except for some operations on arrays. const usedROI = this.rois.find((roi) => roi.id === roiId); usedROI.position.height = position.height; ERROR TypeErro ...

Retrieving information from the Dog API using axios and storing the results in a fresh array

Currently, I am working on a NextJS app using Typescript. My issue lies in the functionality aspect of the application. I am utilizing the Dog API to retrieve all the breeds names and store them in a new array of arrays. Each sub-array contains the breed a ...

Is there a way for me to retrieve a variable from within a .then function nested within another .then function?

Here is an example of code where I am attempting to log the value of 'a' to the console. driver.sleep(2000).then(function logAInConsole() { var a = ["Quas","Wex","Exort","Invoke"]; for(var i = 0; i < a.length; i++) { driver.sleep( ...

Invoking AJAX function post readystatechange

Currently, I am in the process of making an Ajax call to a server and attempting to invoke another function once the response is ready (readystatechanged). As of now, there isn't any serverside code implemented. Surprisingly, Chrome and Firefox encoun ...

Leverage the power of JavaScript validation combined with jQuery

Hello, I'm relatively new to the world of Javascript and jQuery. My goal is to create a suggestion box that opens when a user clicks on a specific button or div element. This box should only be visible to logged-in users. I have some knowledge on how ...

` Detecting initialized properties of classes using Eslint rule`

When useDefineForClassFields:true is used, the code below becomes invalid when targeting es2022: Cannot read properties of undefined (reading 'array') class Bar { array = new Array(); } class Foo { foo = this.bar.array; // Property &apo ...

Show images exclusively on screens with a smaller resolution

Looking for assistance in modifying the code below to only display the image in mobile view, instead of constantly appearing. <style type="text/javascript> .icon-xyz {float: left; width: 22px;cursor: pointer;background: none;} @me ...

Encountered issue in Angular: Object prototype must be either an Object or null, not undefined

I encountered an issue with my Angular application when trying to install npm dependencies using npm i. I kept receiving a "sha1 seems to be corrupted" error. To resolve this, I deleted the package-lock.json file and was able to successfully install all th ...

Tracking and managing user clicks on external links within a vue.js application

I am currently working on a web application that retrieves data from a CMS. Utilizing the Vue-Router in 'history' mode, I need to address content fetched from the API which may include links. My goal is to manage specific links using the router w ...

What is the best approach to slowly transition a value to a different one over a set period of time?

if(!isWalking) { isWalking = true; var animation = setInterval(function () {$player.css({'left': "+="+boxSize/25})}, 10); setTimeout(function(){clearInterval(animation)},250); setTimeout(function(){isWalking = false},250); ...

Tips for including additional properties to a <button> element using ReactJS and Typescript

Currently, I am in the process of creating a unique component which consists of an ordinary <button> tag and has a new prop called aria-current. The issue at hand is that Typescript is flagging an error stating that this property does not exist with ...

What is the best way to transfer a JavaScript variable through a query string from one HTML page to another?

Is there a way to pass a JavaScript variable called username from one HTML page, example1.html, to another HTML page, example2.html, using query strings? <script type="text/javascript" > $(document).ready(function() { $('#SubmitForm ...

Creating subclass mappings and defining subclasses dynamically using Typescript at runtime

I am puzzled by the structure of 3 classes: A, B, and C. Both B and C extend the abstract class A. abstract class A { public name: string; constructor(name: string) { this.name = name; } abstract getName(): string; } class B extends A { g ...

Ways to inform TSC that script files won't have shared scope and should disregard redeclarations

Issue to Resolve I am utilizing the TypeScript-powered JavaScript checking capabilities of VSCode to perform type-checking on multiple JS files. These files are intended to be imported via <script> tags in HTML and do not contain any export/import s ...

Regularly switch up the background image using the same URL

I am currently developing an angular JS application where the background of my body needs to change every minute based on the image stored on my server. In my HTML file, I am using ng-style to dynamically set the background image: <body ng-controller= ...

Within the realm of Ionic/Angular2/AngularFire2, when a Firebase query is conducted and an array is present, the returned value

The following code snippet is designed to retrieve an object from Firebase, specifically an array. this.item2 = this.af.object('/profiles/' + this.username + '/followers'); this.subscription5 = this.item2.subscribe(item => { ...

Validation for a datepicker embedded within a table

I'm facing a challenge and need some assistance. I want to validate if the "FROM (DATE)" is greater than the "TO (DATE)" without disabling the date selection, but instead prompting the user if the condition is not met. Any insights or solutions would ...

Is it possible to automatically set focus on the input box in an html tag multiple times instead of just once with autofocus?

Currently, I am developing an online editor that allows users to quickly edit individual words. My approach involves replacing specific words with input boxes containing the word for direct editing by users. In order to streamline the process and ensure e ...

Building a personalized payment experience using Python Flask and Stripe Checkout

I'm attempting to set up a customized checkout integration with Stripe on my Flask web application and I've encountered some issues. After copying the code from the Stripe documentation (located at https://stripe.com/docs/checkout#integration-cu ...

The PhpStorm code completion feature is not functioning properly when working with TypeScript code that is distributed through NPM

I am facing an issue with two NPM modules, which we will refer to as A and B. Both modules are written in TypeScript and compile into CommonJS Node-like modules. Module B has a dependency on module A, so I have installed it using the command npm install ...