Transform webservice data into TypeScript object format, ensuring mapping of objects from capital letters to camel case

Something peculiar caught my attention in my Angular2 TypeScript project. When objects are fetched from a web service, they have the type "Level" and the properties are in Pascal case. However, during runtime, I noticed that the properties of these Levels have lowercase letters in my TypeScript project (as seen in the browser's developer debug tool).

I believe I need to somehow map the JSON properties instead of using "as Level[]" for casting everywhere. How can I achieve this properly?

Update: In response to requests for code samples:

(Controller)

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

(Service)

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

Update: I made some improvements to my code with help from a previous answer (not included above as it does not address the main issue). I attempted to implement another suggestion to convert to camel case but encountered difficulties accessing object properties within an array.

Update: Success! After hours of searching, I finally found a solution (!). I've condensed this post and will share my solution below. It may not be perfect, but I'm grateful for all the helpful advice provided here!

Answer №1

If you want to retrieve the objects in lowercase, you can utilize this method.

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

You can then proceed to return the transformed data

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

Answer №2

You've overcomplicated both methods. Simplify it as:

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

// Handle errors
private handleError(error: Response) {
        console.log(error);
        return Observable.throw(error.json().error || 'Internal Server error');
}   

Use TypeCasting in your service method like this:

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

The component should send the request to the service on initialization:

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

}  

Declare variables like this:

levels: Level[];

Answer №3

After hours of hard work and research, I have finally found a solution! Although it may not be the most elegant one, it is easy to grasp and comprehend:

function extractLevelProperties(response: any): Level[] {
    let levels: Level[] = [];
     Object.keys(response).forEach((key) => {
       // Create a new object by extracting only the necessary information from the JSON data.
       // Since the webservice uses Pascal case letters, we need to convert them into camel case format.
      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;
  };

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

Exploring the world of TypeScript interfaces and their uses with dynamic keys

I am hopeful that this can be achieved. The requirement is quite simple - I have 2 different types. type Numbers: Number[]; type Name: string; Let's assume they are representing data retrieved from somewhere: // the first provider sends data in th ...

Creating an API definition in Swagger with multiple objects at varying levels: A step-by-step guide

I am currently working on creating an API in Swagger using YAML. My goal is to establish a global document definition that aligns with the following JSON structure: { "document_info" : { "name" : "string", "file" : "base64" }, "document_d ...

What is the best way to handle a JSON map containing a list of maps retrieved from an API for an HTTP GET request

I'm encountering a persistent error that I can't seem to resolve: NoSuchMethodError (NoSuchMethodError: The method 'map' was called on null. Receiver: null Tried calling: map(Closure: (dynamic) => Name1Name2)) Despite my best effo ...

I'm having trouble getting Remix.run and Chart.js to cooperate, can anyone offer some guidance?

I've encountered a challenge with Remix.run and chart.js (react-chartjs-2) when attempting to display the chart. I followed the documentation and installed the necessary dependencies: react-chartjs-2 and chart.js. Here's the snippet from my pac ...

Having difficulty transmitting data from a view to an API controller

Hey there! I'm currently working on sending JSON data to the API controller through a HttpPost request to add that data to a file. This is what my JSON File looks like: { "students": [ { "Id": 1, "Name": "Ra ...

Handling routerLink exceptions in Angular 2, 4, and 5

In my app, I am working on catching routing exceptions. There are three ways in which a user can navigate: If the user types the address directly - this can be caught easily by using { path: '**', redirectTo: 'errorPage'} in the route ...

Is there a way to turn off TypeScript Inference for imported JavaScript Modules? (Or set it to always infer type as any)

As I attempt to utilize a JS module within a TypeScript File, I encounter errors due to the absence of type declarations in the JS module. The root cause lies in a default argument within the imported JS function that TypeScript erroneously interprets as ...

Enhancing the internal styling of ngx-charts

While working on the ngx-charts Advanced Pie Chart example, I noticed that the numbers in my legend were getting cut off. Upon inspecting the CSS, I discovered that a margin-top of -6px was causing this issue: https://i.stack.imgur.com/oSho1.png After so ...

What is the reason behind TypeScript failing to provide type safety in a generic higher order component which introduces extra properties into React components?

I'm currently working on developing a versatile higher order component, but have encountered an issue with type safety not being enforced. Interestingly, when attempting the same implementation without using generics, the type safety is verified as ex ...

Utilizing ngx-pagination for repetitive instances of a single component

I have encountered an issue with the ngx-pagination library in my reusable data table component. While it works perfectly for a single instance, using it multiple times causes the pagination to only function on one of the components. Is there a way to make ...

Observing the data retrieved from an AJAX request

Currently, I have this AJAX call in my code: $('#search').keyup(function() { $.ajax({ type: "GET", url: "/main/search/", data: { 'search_text': $('#search').val() }, suc ...

Is there a way to accurately capture the timestamp of when a user clicks the submit button in Angular 2 framework?

Within my HTML file, I have implemented an onRegisterSubmit() function to handle the submission of a form. The register.ts file is responsible for adding user input from the form, as well as validating and authenticating the user. onRegisterSubmit(){ ...

Error encountered while building with Next.js using TypeScript: SyntaxError - Unexpected token 'export' in data export

For access to the code, click here => https://codesandbox.io/s/sweet-mcclintock-dhczx?file=/pages/index.js The initial issue arises when attempting to use @iconify-icons/cryptocurrency with next.js and typescript (specifically in typescript). SyntaxErr ...

Encountering issues in Angular 2 when attempting to pass data into root component through ng-content and binding. Objective: Creating a reusable form component

I currently have a .NET MVC application and I'm looking to integrate Angular 2 into it. The structure of my page is as follows: <html> <head>css imports and jquery imports</head> <body> <div> a bunch of table ...

Can a new record be created by adding keys and values to an existing record type while also changing the key names?

If I have the following state type, type State = { currentPartnerId: number; currentTime: string; }; I am looking to create a new type with keys like getCurrentPartnerId and values that are functions returning the corresponding key's value in Sta ...

What is the best approach to transform an HTML textarea value into JSON format?

Client .. inserting some content into a form <textarea name="data"></textarea> After typing the following data into the textarea: {title: 'Hello one!', author: 'someone'} {title: 'Hello two!', author: 'mygf ...

What is the syntax for creating a link tag with interpolation in Angular 2 / Ionic 2?

As I work on developing an app using Ionic 2/Angular 2, I have encountered a challenge that I am struggling to overcome. Let me provide some context: I am retrieving multiple strings from a webservice, and some of these strings contain links. Here is an e ...

Angular Material Spinner with Custom Image Icons - (mat-spinner)

I have successfully implemented the mat-spinner in my project with configurable changes like color and mode of spinning. However, I am now looking to add an image icon, specifically the logo of a brand or company, inside the spinner. How can I achieve this ...

The Ionic Keyboard close event does not trigger

I am attempting to automatically hide the keyboard when the user scrolls within the app. Here is my code snippet: .html <ion-content class="maincontent" (ionScrollStart)="scrollStart()"> <router-outlet></router-outlet> </ion-conten ...

Enhancing React Flow to provide updated selection and hover functionality

After diving into react flow, I found it to be quite user-friendly. However, I've hit a roadblock while attempting to update the styles of a selected node. My current workaround involves using useState to modify the style object for a specific Id. Is ...