ANGULAR – Mapping nested JSON data from API

so I’ve been struggling for the past day or so with mapping the response from a mock API – I think I’m mapping it correctly but when I try to access the data it doesn’t return anything in the HTML.

Please find my code below:

data.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ConsentData, Prompt } from '@app/models/consent-data';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class ConsentWebviewDataService {
  constructor(private httpClient: HttpClient) {}

  getConsentData(): Observable<ConsentData<Prompt>> {
    return this.httpClient.get<ConsentData<Prompt>>(
      'MY_API_URL',
    );
  }
}

data.ts (interface)

export interface ConsentData<Prompt> {
  prompts: Prompt[];
}

export interface Prompt {
  promptId: number;
  headline: string;
  body: string;
  imageUrl: string;
  consents: string[];
  type: string;
}

app.component.ts

export class PromptComponent implements OnInit {
  consentData: any;

  constructor(private consentWebviewDataService: ConsentWebviewDataService) {}

  ngOnInit(): void {
    this.consentWebviewDataService.getConsentData().subscribe(data => {
      this.consentData = data.prompts.map(consents => {
        return {
          promptId: consents.promptId,
          headline: consents.headline,
          body: consents.body,
          imageUrl: consents.imageUrl,
          consents: consents.consents,
          type: consents.type,
        };
      });
    });
  }
}

Lastly here is the API JSON response:

{"prompts":[{"promptId":100,"headline":"Headline","body":"Body text.","imageUrl":"https://picsum.photos/200","consents":["Consent 1","Consent 2","Consent 3"],"type":"ConsentCampaign"}]}

From what I understand so far, after countless tutorials and resources, the getCosentData() function sends request to API, then in the component I subscribe to it, get the response, assign the response to the consentData variable, then map the contents of the response based on the interface / how the JSON response looks.

However, the problem is that I cannot access the mapped data in the HTML. I don’t need it in a table, just need to get the mapped data.

I tried all variations such as {{ consentData.promptId }} which I mapped, and it returns ERROR TypeError: ctx.consentData is undefined. Tried {{ consents.promptId }} as well, etc. but nothing works.

What am I missing here? And apologies for the long question && thanks in advance for any help!

>Solution :

It looks like your code is correctly mapping the response from the API to the consentData variable in the PromptComponent class. However, it seems that the issue is with accessing the data in the HTML template.

One thing that might be causing the issue is that the consentData variable is not being initialized in the PromptComponent class before the API call is made. It’s currently set to any type. You can initialize it to an empty array so that the HTML template can render the data properly.

export class PromptComponent implements OnInit {
  consentData: any[] = [];
  // ...
}

Another thing to keep in mind is that the data may not be available immediately when the template is rendered. The data is being loaded asynchronously via the API call, so it may take some time before it becomes available. To handle this, you can use the *ngIf directive to only display the data once it’s available.

<div *ngIf="consentData">
  <div *ngFor="let consent of consentData">
    {{ consent.promptId }}
    {{ consent.headline }}
    {{ consent.body }}
    {{ consent.imageUrl }}
    {{ consent.consents }}
    {{ consent.type }}
  </div>
</div>

This way, the template will only display the data when the consentData variable is not empty and contains data.

Another thing, you might want to check is the subscribe call, it might not be getting the data or the call is taking too long to return.
You can check it by console.log the data inside the subscribe and see if the data is coming as expected or not.

Leave a Reply