Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse JSON to Typescript class in Angular app

I'm creating a app usign angular and typescript. Everything is comming together nicely, but one issue bugs me.

I define entity/model classes that i would like to pass around in the app, the data for the classes comes from JSON from $resource calls.

Here is an example of a model class:

module app.domain {

    export interface IJob {
        id: number;
        jobTitle: string;
        jobDescription: string;
    }

    export class Job implements IJob {

       constructor(public id:number, public jobTitle: string, public jobDescription: string) {

       }
    }
}

I access my JSON resource through a service that returns the resource:

namespace app.services {
    'use strict';

    interface IDataService {
        getJobResource(): angular.resource.IResourceClass<IJobResource>
    }

    interface IJobResource extends angular.resource.IResource<app.domain.IJob>{

    }

    export class DataService implements IDataService {

        static $inject: Array<string> = ['$log','$resource','ApiDataEndpoint'];
        constructor(
                    private $log: angular.ILogService,
                    private $resource: angular.resource.IResourceService,
                    private ApiDataEndpoint          
            ){}

        getJobResource(): angular.resource.IResourceClass<IJobResource>{
            return this.$resource(this.ApiDataEndpoint.url + 'job/:id',{});
        }
    }

    angular
        .module('app.services',[])
        .service('dataService', DataService);
}

This is where it goes wrong, when I cast the result of the resource call to Ijob typescript restrict me to call properties that don't match the names in the interface (as expected) but because this is still just JSON I'm unable to make method calls and if the properties en the IJob interface do not match the names in the JSON result the I get nothing.

So, my questing is: What is the correct way to implement a service that calls a restfull endpoint that returns JSON and then returns an array of objects or a single object. The way should support that names on JSON and on the objects might not match.

like image 927
iCediCe Avatar asked Jan 19 '16 10:01

iCediCe


1 Answers

You could make a class that has the functionality you need and gets a IJob object to work with.

module app.domain {

    export interface IJob {
        id: number;
        jobTitle: string;
        jobDescription: string;
    }

    export class Job {
       // keep the data received from the server private
       constructor(private jobData: IJob) {}

       // class methods
       public isIdGreaterThanTen(): boolean {
         return this.jobData.id > 0;
       }

       // expose the properties of the IJob interface via getters and setters
       public get id(): number { 
         return this.jobData.id;
       }

       public set id(id: number): void {
         this.jobData.id = id;
       }

       // so on for all properties if needed
       // ...

    }
}

In the service you can use the transformResponse functionality of $resource to create and return a new instance of the Job class instead of the object returned by the server.

namespace app.services {
    'use strict';

    interface IDataService {
        getJobResource(): angular.resource.IResourceClass<IJobResource>
    }

    // use the Job class instead of the interface
    interface IJobResource extends angular.resource.IResource<app.domain.Job>{

    }

    export class DataService implements IDataService {

        static $inject: Array<string> = ['$log','$resource','ApiDataEndpoint'];
        constructor(
                    private $log: angular.ILogService,
                    private $resource: angular.resource.IResourceService,
                    private ApiDataEndpoint          
            ){}

        getJobResource(): angular.resource.IResourceClass<IJobResource>{
            return this.$resource(this.ApiDataEndpoint.url + 'job/:id',{},
            {
              get: {
                method: 'GET',
                transformResponse: function(data: IJob) {
                  return new Job(data); // create a new instance of the Job class and return it
                }
              }
            });
        }
    }

    angular
        .module('app.services',[])
        .service('dataService', DataService);
}
like image 150
toskv Avatar answered Oct 19 '22 22:10

toskv