Struggling to map the response data received from an http Get request to a TypeScript object that follows a similar structure

Currently, I am invoking an http Get service method from a component to retrieve data and map it to a Person object. The goal is to display this information on the front end.

Below is my component code:

export class DisplayPersonComponent implements OnInit {

  personId: number;
  person: Person;
  
  constructor(private route: ActivatedRoute, private service : PersonService) { }

  ngOnInit() {
    this.route.params.subscribe(params => {
       this.personId = params['person-id']});    
       
       this.getPerson(this.personId);
  }

  
    getPerson(id: number)
    {
        this.service.getPerson(id).subscribe((data: Person) => { console.log(data); 
          this.person = data
         });
    }
}

And here is my service method:

getPerson(personId : number): Observable<Person> {

    let urlParams = new HttpParams().set("personId", personId.toString());

    return this.http.get<Person>(this.apiUrl, { params:  urlParams})
      .pipe(map((data: Person ) => { return data }),
        catchError(error => { return throwError(' Something went wrong! ');
        })
      );
  }
}

After inspecting the returned data object in the component, it appears to be in json format like { PersonID: 1, Name: 'Name'} etc. However, the issue lies in the fact that this.Person always remains undefined without any clear output or error explanation.

It is also important to note that I utilize the same objects for a POST method, which seamlessly maps from client to server without any specified mapping.

Answer №1

At the moment when getPerson() is called, the variable this.personId is assigned asynchronously and remains undefined.

To simplify the code and avoid nested subscriptions, consider using the RxJS higher order mapping operator switchMap to switch from one observable to another.

ngOnInit() {
  this.route.params.pipe(
    switchMap(params => this.service.getPerson(params['person-id']))
  ).subscribe((data: Person) => {
    console.log(data);
    this.person = data;
  })
}

Option 2: async pipe

If you do not need to use this.person in the controller, you can omit the subscription and utilize the async pipe in the template instead.

Controller

import { Observable } from 'rxjs';

export class DisplayPersonComponent implements OnInit {
  person$: Observable<Person>; // <-- define type as `Observable`
  
  constructor(private route: ActivatedRoute, private service : PersonService) { }

  ngOnInit() {
    this.person$ = this.route.params.pipe(
      switchMap(params => this.service.getPerson(params['person-id']))
    );
  }
}

Template

<ng-container *ngIf="(person$ | async) as person">
  {{ person }}
  <some-comp [person]="person">...</some-comp>
</ng-container>

Update: Cannot read property

The error occurs because the person variable is undefined until a value is assigned within the subscription. Using the second option with async can help resolve this issue. Alternatively, you can use the safe navigation operator ?. to check if a variable is defined before accessing its properties.

<div>
  {{ person?.personId }}
  {{ person?.someProp }}
  {{ person?.someOtherProp }}
</div>

For more information on handling asynchronous data, refer to this resource.

Answer №2

Observers are asynchronous; when you're processing the person variable, the function within the subscribe method that executes once the observable is complete hasn't been triggered yet.

I'm not sure how you're utilizing the person object, but it appears that some adjustment to your logic may be necessary.

Thankfully, Angular provides the async pipe which can be paired with *ngIf in the following manner:

<div *ngIf="(getPerson(personId) | async) as person">

This pipe takes an observable and "resolves" it to the person object within the HTML template. It only displays the content inside after the request is completed, allowing you to freely access the object's properties!

For additional details and the original source:

Answer №3

When calling your service method, keep in mind that it returns an observable instead of the person directly. This means that if you try to access the person object before the observable has actually returned a value, it will be undefined. This behavior isn't a bug, it's just how asynchronous code operates.

To handle this in your markup, make sure to check if the object is undefined before trying to render it:

<div *ngIf="person">...</div>

The reason your POST method may appear to work without issues is because you may not be actively doing anything with the response. However, if you wanted to perform actions based on the success or error of the POST request, similar principles would apply - you need to observe the POST response and take appropriate action accordingly.

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

Post-Angular migration (going from version 12 to 14), there are still lingering security risks associated with the "d3-color vulnerable to ReDoS" issue

Following the migration to Angular 14, I made sure to update my "@swimlane/ngx-charts" version to "20.1.2" and the "d3" version to "7.8.4". However, even after running the npm install command, I am still encountering 5 high severity vulnerabilities in my p ...

Updating the data attribute of an object in HTML using Angular

I am trying to embed a PDF viewer inside a component. In order to dynamically update the PDF document within a sanitizer, I need to use an attribute with []. This works fine with images. <img src="assets/pic.jpg"/> <img [src]="'assets/pi ...

When I attempt to make an HTTP request in Angular, I can see my x-access-token, but for some reason the request is coming back

onTable(){ let headers = new HttpHeaders(); //headers.set('Content-Type', 'application/json'); //headers.set('x-access-token', this.token).set('Content-Type', 'application/json'); console.log("this is ...

How can we combine two phone calls and display the outcomes using typeahead ngx-bootstrap?

Let me walk you through the code that is currently working: <input [formControl]="search" [typeahead]="suggestions" typeaheadOptionField="name" (typeaheadOnSelect)="onSelectedDriver($event)&qu ...

Error message in Typescript with React: "The type 'ComponentClass<StyledComponentProps<{}>>' cannot be assigned to type 'typeof MyComponent'"

Currently experimenting with integrating the Material UI 1.0 (beta) @withStyles annotation into a React component. The documentation provides a JavaScript example (), however, it results in a compilation error when using Typescript. Despite the error, the ...

Creating a Tailored Validation Function in Angular 6

Looking to develop a custom generic validator that accepts the regular expression pattern and the property name (from a formgroup) as parameters? Take a look at this code snippet: UserName: new FormControl('', [ Validators.require ...

When you use array[index] in a Reduce function, the error message "Property 'value' is not defined in type 'A| B| C|D'" might be displayed

Recently, I delved deep into TypeScript and faced a challenge while utilizing Promise.allSettled. My objective is to concurrently fetch multiple weather data components (such as hourly forecast, daily forecast, air pollution, UV index, and current weather ...

The issue with Vuex and Typescript is that when using mutation object payloads, they are consistently undefined

Every time I run my code, the object payload I'm passing as a secondary parameter to my Vuex mutation method ends up being undefined. Both my Vuex and component files are coded in TypeScript. When looking at my index.ts file for my Vuex store (where ...

Typescript is failing to perform type checking

I'm encountering an issue while trying to utilize TypeScript type checking with the following code snippet: abstract class Mammal { abstract breed(other: Mammal); } class Dog extends Mammal { breed(other: Dog) {} } class Cat extends Mammal { ...

I am working with an array called officeLocations, and I am looking to showcase it in an HTML format using the isOpened property in Angular

In my officeLocation.ts file, I have an array called officeLocationsArray structured like this: export class OfficeLocation { officeLocationName:string; Isopened:boolean; } export const officeLocationArray : OfficeLocation[] = [ {officeLocatio ...

Tips for accessing and modifying local files in Angular 2

Is there a method in Angular 2 to access files from an absolute path? I have utilized the 'filesaver' library for file saving, storing the files locally in txt/json formats. For instance: let blob = new Blob([document.getElementById(&apos ...

The dynamic form functionality is experiencing issues when incorporating ng-container and ng-template

I'm currently working on a dynamic form that fetches form fields from an API. I've attempted to use ng-container & ng-template to reuse the formgroup multiple times, but it's not functioning as anticipated. Interestingly, when I revert b ...

Cannot find property in type, and the parameter is implicitly of an unspecified type

I've been encountering this issue where I keep getting an error message. I attempted to resolve it by setting "noImplicitAny": false in tsconfig.json, but unfortunately that did not work. As for the 'Property does not exist on type' error, I ...

TS7030: In Angular13, ensure that all code paths within the guard and canActivate methods return a value

Having trouble using guards for an unlogged user and constantly facing errors. Error: TS7030 - Not all code paths return a value. Below is my auth.guard.ts file: import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from &a ...

How to minimize xAxes labels in Chart.js

As a newcomer to Chart.js, I am encountering some challenges. My goal is to create a bar chart that displays hourly information. However, when attempting to show data for a week, a month, or an extended period, I face issues with reducing the labels on the ...

What is the significance of the message "JavaScript files do not have any valid rules specified"?

I am working on a React - Typescript project that was created using the following command: create-react-app my-app --scripts-version=react-scripts-ts While it compiles without any issues, I keep receiving a message or warning that says: No valid rules h ...

What is the best way to effectively handle the proxying of objects across multiple levels?

As illustrated in a Stack Overflow thread, utilizing Proxy objects is an effective method for monitoring changes in an object. But what if you need to monitor changes in subobjects? In such cases, you will also have to proxy those subobjects. I am curren ...

Send the Children prop to the React Memo component

Currently, I am in the stage of enhancing a set of React SFC components by utilizing React.memo. The majority of these components have children and the project incorporates TypeScript. I had a notion that memo components do not support children when I en ...

Using TypeScript and webpack, include the access_token in the http header when making requests with axios

I need to include an access_token in the header of axios, following this example: https://github.com/axios/axios#global-axios-defaults Currently, I am fetching the access_token using razor syntax, which is only accessible in CSHTML files. https://github ...

Using TypeScript to ensure class parameter types without affecting properties

I am tasked with defining a schema for "operations" that will be used in my application. This schema must be easily extendable for other groups of "operations" and should include a dictionary of settings for each keyword. Eventually, a "generic caller" wi ...