2

I have a Student Java Script object as follows:

function Student(name, grade){
    this.name = name;
    this.grade = grade;
}

I know I can store and retrieve this object to/from Local Storage using JSON.stringify() and JSON.parse() method. It works fine. But my problem is below.

I want to introduce a new property 'subjects' of Set() type that takes unique values and store this Student object in Local Storage. My saveStudent() method is as follows:

function saveStudent () {
    student = new Student("Rajib","1st");

    var subjects = new Set();
    subjects.add("Mathematics");
    subjects.add("Science");
    subjects.add("English");
    console.log(subjects);
    student.subjects = subjects;

    window.localStorage.setItem("student", JSON.stringify(student));
}

I can store this object in Local Storage without any error and also my console displays the 3 subjects properly. But when I try to retrieve this Student object from Local Storage, I get Student object with all the values except 'subjects' which is empty. May I know why?

My getStudent() method is as follows:

function getStudent () {
    var student = JSON.parse(window.localStorage.getItem("student"));
    console.log(student);
}

My console shows

Object { name: "Rajib", grade: "1st", subjects: {} }

Is there anyway to store nested object(where property of object contains another object) as such in Local Storage and retrieve with all its properties and values?

Note: I can solve the above by serializing to String of Subjects and then deserializing again. But I want to avoid that and want to do it in pure Java Script or OOPs way.

Igwe Kalu
  • 14,286
  • 2
  • 29
  • 39
RLD
  • 1,867
  • 3
  • 15
  • 20
  • This question has a perspective that the _duplicate_ doesn't share. @RLD, the OP, doesn't understand that issue lies in the nature of the `subject` property - it being a `Set`. However, the poster of the linked question understands that `Set`s cannot be stringified simply, and is looking for a way to achieve that. We can consider this post with a bit more empathy, and thus use the opportunity to educate for improvement. – Igwe Kalu Jul 14 '18 at 22:26
  • Thanks @Igwe Kalu for being considerate. You are right, I thought from nested object perspective, but the problem lies in Set object. – RLD Jul 15 '18 at 15:41

2 Answers2

4

Because Sets in JavaScript don't store its entries as enumerable properties, the entries are not transparent to the JSON.stringify function.

However, by the replacer parameter of JSON.stringify and the reviver parameter of JSON.parse, provisions are given for a means to influence how an item encountered in the serialisation/deserialisation process is handled.

Hence:


function Student(name, grade, subjects) {
  this.name = name;
  this.grade = grade;
  this.subjects = subjects || new Subjects();
}

function saveStudent(student) {
  var studentObjectAsSerialisedData = JSON.stringify(student, function(propertyKey, propertyValue) {

    // Store a set in the form a list that can be used to recreate it
    if ("subjects" === propertyKey) {
      return Array.from(propertyValue);
    }

    return propertyValue;
  });

  window.localStorage.setItem("student", studentObjectAsSerialisedData);
  console.log("saved:", studentObjectAsSerialisedData);
}

function getStudent() {
  var studentObjectAsSerialisedData = window.localStorage.getItem("student");
  var student = JSON.parse(studentObjectAsSerialisedData, function(propertyKey, propertyValue) {
    // Restore subjects from list to the set form
    if ("subjects" === propertyKey) {
      return new Set(propertyValue);
    }

    // Everything else is returned as is
    return propertyValue;
  });

  student.subjects = new Set(student.subjects);

  console.log("loaded: ", student);
  console.log("loaded subjects of student: ", Array.from(student.subjects));
}

var subjects = new Set(["Mathematics", "Science", "English"]);
var student = new Student("Rajib", "1st", subjects);
saveStudent(student);

var storedStudent = getStudent();
Rick
  • 4,030
  • 9
  • 24
  • 35
1

The reason of this is that JSON.stringify(set) always returns '{}'. You should pass JSON.stringify method replacer function to convert set of subjects into array like this: Array.from(set) and then save this version. Then after getting student object from localstorage you should convert subjects array back to set. So your code should look like this:

function saveStudent () {
    student = new Student("Rajib","1st");

    var subjects = new Set();
    subjects.add("Mathematics");
    subjects.add("Science");
    subjects.add("English");
    console.log(subjects);
    student.subjects = subjects;

    var stringifiedVersion = JSON.stringify(student, function (key, val) {
        if (val instanceof Set) {
            return Array.from(val);
        }
    })

    window.localStorage.setItem("student", stringifiedVersion);
}

function getStudent () {
    var student = JSON.parse(window.localStorage.getItem("student"));
    student.subjects = new Set(student.subjects);
    console.log(student);
}
Gaiozz
  • 111
  • 3