Home > Enterprise >  The data from backend is not getting an Angular class / prototype
The data from backend is not getting an Angular class / prototype

Time:05-17

I'm developing a frontend in Angular and a backend in Spring. I have a problem when I fetch the data from the backend, the data isn't inheriting the methods of the class it's supposed to belong. I'm getting this error in the Mozilla's console:

ERROR TypeError: skill_r1.getNombre is not a function

I don't understand why, because I'm specifying that the data fetched from the api is of type "Skill[]"... I mean, every property's name is what it's supposed to. This is what is fetching from the backend:screenshot from browser's console with data from API If I replace the fetched data from the backend with a mock data created in Angular itself, it works like charm, as you can see here.

This is the Angular class (plus getters and setters for each value):

export class Skill{
private nombre : String;
private color : String;
private valor : number;
private id : number;

constructor(
    nombre : String,
    color : String,
    valor : number,
    id :number
    ){
        this.nombre = nombre;
        this.color = color;
        this.valor = valor;
        this.id = id;
    }

this is the code for the Service:

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

@Injectable({
    providedIn: 'root'
})
export class SkillService {
    skills: Skill[] = [];
    constructor(        
        private api:HttpClient
    ) {}

get(): Observable<Skill[]> {        
        return this.api.get<Skill[]>(Backend_URL   "/skills")
}

And this is the code of the component:

import { Component, OnInit } from '@angular/core';
import { Skill } from 'src/app/clases/Skill';
import { SkillService } from 'src/app/services/skill.service';    

@Component({
    selector: 'app-skills',
    templateUrl: './skills.component.html',
    styleUrls: ['./skills.component.css'],
})
export class SkillsComponent implements OnInit {
    skills: Skill[] = [];

    constructor(        
        private skillService:SkillService ) { }

    ngOnInit(): void {
        this.skillService.get().subscribe((skillsDesdeApi)=>{
            this.skills = skillsDesdeApi;            
        })        
    }

Thank you so much yor stopping by!

CodePudding user response:

I don't know (since you haven't posted the relevant code) exactly what this.api.get does, but if it's like (or using) the Angular HttpClient, or is doing a fetch, then adding the type, e.g. this.api.get<Skill[]>() does not actually create instances of the type. It's just a type cast, telling it to treat the result as that type, not actually converting it.

This works well for pure data classes (no methods), because the returned JSON object is an object literal, and (presumably) has the same properties as the specified type.

So, if you want instance of a type with methods, you'll have to create the object yourself from the JSON.

CodePudding user response:

As GreyBeardedGeek already stated, in your call return this.api.get<Skill[]>(Backend_URL "/skills") specifying <Skill[]> only adds typing information that helps you writing code in your IDE. When the http client gets the raw string from the backend it is only parsed as JSON and therefore the result will just be a dictionary.

A simple solution for this problem is using class-transformer.

import { plainToInstance } from 'class-transformer';

this.api.get<Skill[]>(Backend_URL   "/skills").pipe(map(plain => plainToInstance(Skill, plain)))

The plainToInstance function will transform the plain dictionary to an array of Skill objects which is what you need in order to be able to call the functions from Skill.

  • Related