3

I want to use Angular 2 to make a browser app where you can make and share mock exams. I have a Exam class instance containing ExamSection class instances which contain ExamQuestion class instances etc.

I want for the app to be able to save and load the exams as JSON. My current solution is:

constructor(private http:Http) {
    this.http.get('Exam.json')
            .map((response) => {
              return response.json();

            }).subscribe(data => {
              this.exam = <Exam>data;
              //console.log(typeof(<Exam>data));
              console.log(this.exam);
              this.refreshMarksMethods(this.exam);
            });

}

The first issue is that the JSON is deserialized as a plain object. I attempted to use serializer.ts (https://www.npmjs.com/package/serializer.ts) and class-transformer(https://github.com/pleerock/class-transformer) to do serialization and deserialization for the TypeScript classes that Angular works with but I keep getting errors relating to missing modules. The modules that are missing are not referenced in the examples for those libraries, as far as I can work out, so I don't know where they belong.

A trick I tried to work around the issue was to cast the plain objects into the needed Typescript type but this doesn't work (the object type does not change). Because the objects are plain objects, I loose the methods and also properties like length (for arrays).

Can someone please explain to me how I'd go about converting TypeScript objects to and from JSON within a Angular app, including how and where the required libraries go? Sometimes putting the module in the "node_modules" folder works, and sometimes it belongs somewhere in the "src" folder (I have to work this out with trial-and-error usually).

Edit: I got a hacky solution working where the objects described in the JSON have a "deserialize" method which is used to recursively reconstruct the class instances. I'm hoping someone can explain how to use a different solution because I doubt my current solution will work for large projects.

Dev243
  • 53
  • 1
  • 6
  • Have you looked as this? https://stackoverflow.com/questions/22875636/how-do-i-cast-a-json-object-to-a-typescript-class Now you are not actually creating *instances* of your class, but just telling the compiler that you expect the data to be of type `Exam`. – AT82 Oct 27 '17 at 18:35
  • I looked through the solutions there and nothing seemed to work other than the hacky solution of a "deserialize" method (which I only just got working) which is not a scalable solution. I'm hoping someone can explain how to use a better method. – Dev243 Oct 27 '17 at 22:37
  • So I assume you have somewhere a class with methods, properties etc. and you want the unserialized data to be an instance of that class, right? I think it's not possible, but correct me if I am wrong. There are solutions for that, eg: to have an update method on the object - basically you create a new instance of that `Exam` and update it by the data from JSON. Simple, classes are matching, but it would require some coding as it wont happen automatically (a good example for that kind of magic is PHPs `unserialize` function). – roomcayz Oct 27 '17 at 22:55
  • I remember seeing libraries and code that would supposedly preserve the methods. However I've gone through so many libraries and solutions that I'm not sure which are the ones that said they would "preserve the methods". Solutions like serializer.ts (https://www.npmjs.com/package/serializer.ts) do require a bit of work for non-trivial things like nested objects but it's far less work that coding a full deserialize method (you just add annotations). – Dev243 Oct 28 '17 at 07:56

1 Answers1

1

I made a little package called json-dry. It supports (circular) references and also class instances.

You have to define 2 class methods (toDry on the prototype and unDry as a static method), register the class, and off you go.

I've been using it for years and it's able to serialize very large collections, too.

Jelle De Loecker
  • 20,999
  • 27
  • 100
  • 142