0

I have the code shown below. When I try to set data returned from a service (the assetGroup variable) the value being set is null. My best bet is it is because not all nested arrays are typed, and needs to be mapped. So my question is two fold, is this the reason why the object continue being null after I set it? And if yes can you somehow do an assign that makes a deep mapping or whats the best approach here?

export class Asset {
    constructor(obj: any) {
        Object.assign({}, obj);
    }
    assetId:number;
    assetSubGroupId:number;
    code: number;
    name: string;
}

export class AssetGroup {

    constructor(obj: any) {
        Object.assign(this, obj);
     }
    assetGroupId:number;
    code: number;
    name: string;
    assetSubGroupList:Asset[];   
}

export class AssetSubGroup {

    constructor(obj: any) {
        Object.assign(this, obj);
     }
    assetSubGroupId:number;
    assetGroupId:number;
    code: number;
    name: string;
    assetList: Asset[];   
}

This is my service:

getAssetGroup(id:number):Observable<AssetGroup>{
    var url = `http://xxx.azurewebsites.net/api/assetgroups/${id}`;
    return  this.httpClient.get<AssetGroup>(url).pipe(map(x => new AssetGroup(x)));    
  }

My component:

private  assetGroup:  AssetGroup;

loadAssets(id)
{   
  this.apiService.getAssetGroup(id).subscribe((data) => {
    this.assetGroup  =  data;      
    console.log(this.assetGroup);  // <---- assetGroup is NULL?
  });
}

Debugger: enter image description here

1
  • to do a deep merge use one of the lodash functions discussed here - stackoverflow.com/questions/19965844/… - deep merge is not straightforward in vanilla JS Commented Sep 26, 2018 at 8:30

1 Answer 1

1

Yes you need to explicitly map the response to your classes. The generics in Typescript just work to ensure that you do not try to access any properties that do not exist, but HttpClient does not create instances of the classes for you. For more also check this discussion on github: https://github.com/angular/angular/issues/20770

In order for you to work with this, you have two options:

  • for now your classes can just be transferred into interfaces as they do not have any functionality but only describe a contract which properties have to exist. So your example is a perfect scenario for actually just using interfaces. For more on this check this link: https://medium.com/front-end-hacking/typescript-class-vs-interface-99c0ae1c2136
  • if you actually do need the types to be classes you will have to explicitly create instances of them.

You will need to write something like this:

export class AssetGroup {

    constructor(obj: any) {
        assetGroupId = obj.assetGroupId
        code = obj.code;
        name = obj.name;
        assetSubGroupList = any.assetSubGroupList.map(
            asset => new Asset(asset)
        );
    }

    assetGroupId:number;
    code: number;
    name: string;
    assetSubGroupList:Asset[];   

}

Your code does not work, because Object.assign does not return an Object type Asset as it merges an Object of Asset with an Object of type any and thus cannot know what the output type can be described as.

Sign up to request clarification or add additional context in comments.

11 Comments

If going with interfaces, do I then skip the mapping part in my service? Right now I use pipe and map, and add the object to the constructor for mapping, how do you do that with an interface with no constructor?
I just tried changing the classes to interfaces and removed constructor and thereby mapping. Then an Object is returned and assetGroup still remains null.
I cannot quite follow what exactly in your code returns null. AssetGroup is the top level object, no?
Yes its the top level.
So what is the output of the endpoint and what is null after you try mapping it?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.