0

We have a javascript object that contains (a) ordinary properties (strings, arrays of other objects, dates), (b) methods, (c) properties that are jQuery objects.

We need to serialize the parent object and all nested objects to a JSON string to send to the server. As part of this process we want to remove properties that the server doesn't need, and any jQuery objects (which won't serialize due to circular references).

We've tried using the "remover" argument of JSON.stringify but it seems to be ignoring nested objects. We have lodash available. What methodology should we be looking at for this?

var Form = function ($elem, config) {
    this.$elem = $elem;
    this.config = config;
    this.init();
};
$.extend(Form.prototype, {
    constructor: Form,
    config: null,
    $elem: null,
    categoryid: null,
    $sectionModal: null,
    sections: [],
    $sectionList: null,
    addSection: function (data) {
        . . .
    },
    validate: function () {
        . . .
    },
    serialize: function () {
        console.log(JSON.stringify(this, function (key, value) {
            if (value instanceof jQuery) {
                return undefined;
            }
            return value;
        }));
    },
    init: function () {
        this.sections.push(new Section(1, "Section one"));
        this.sections.push(new Section(2, "Section two"));
    }
});
centralscru
  • 6,580
  • 3
  • 32
  • 43

2 Answers2

0

You can employ a convention for transient properties, such as a property name starting with $.

var o = {
  a: "a",
  b: 1,
  c: [2, 3],
  d: {
    a: 1,
    $e: "not this one"
  },
  f: function(y) {},
  $e: "not this one"
};

var serialize = function(x) {
  return JSON.stringify(x, function(k, v) {
    if (!k.startsWith("$"))
      return v;
  });
};

console.log(serialize(o));
// {"a":"a","b":1,"c":[2,3],"d":{"a":1}}
George Polevoy
  • 7,450
  • 3
  • 36
  • 61
0

We have got to the bottom of our original problem, although it raises other questions. Regard the following code (also at https://jsfiddle.net/osy4cook/1/). It seems that properties are only included in the serialization if their values are initialized in the object constructor OR set via methods on the object, but NOT if the properties are initialized by adding them to the prototype. I'm sure there's a simple explanation for this - does anyone know what it is?

EDIT: we had two reasons for defining properties on the prototype. First, so all methods/properties for the "class" were defined in the same place, for clarity. Second, to provide defaults. What we overlooked is that properties of the constructor function are specific to each object created with it, while properties of the prototype are shared by ALL objects. Evidently serializing an object just ignores properties on the prototype. (source: Why defining properties in the prototype is considered an antipattern)

var Section = function(id, title) {
    this.id = id;
    this.title = title;
}
var Form = function () {
    this.sections = [];
    this.myvar1 = 123;
    this.init();
};
$.extend(Form.prototype, {
    constructor: Form,
    myvar1: null,
    myvar2: null,
    myvar3: 999,    
    $sectionModal: $("<div></div>"),
    sections: [],
    myarray: [],
    addSection: function (data) {
        //. . .
    },
    serialize: function () {
        console.log(JSON.stringify(this, function (key, value) {
            if (value instanceof jQuery) {
                return undefined;
            }
            return value;
        }));
    },
    init: function () {
        this.myvar2 = 999;
        this.sections.push(new Section(1, "Section one"));
        this.myarray.push(new Section(2, "Section two"));
        this.serialize();
    }
});
var form = new Form();

Result...

{"sections":[{"id":1,"title":"Section one"}],"myvar1":123,"myvar2":999}
Community
  • 1
  • 1
centralscru
  • 6,580
  • 3
  • 32
  • 43