bunt
bunt

Reputation: 312

Forcing Protobuf.js to ignore unrecognized JS-side fields

In sending objects back and forth between JS (TypeScript actually) and .NET w/ protobuf.js I would like to decorate the JS objects w/ fields only meaningful at runtime (e.g. WebGL context, handles, etc.). Adding a new dynamic field is straightforward:

ReceivedObject.RuntimeField = new RuntimeField();

However, when serializing back up to the server protobuf.js discovers the new field and throws an exception.

I have found I can hack around this by adding the three lines below directly to protobuf.js:

MessagePrototype.set = function (keyOrObj, value, noAssert) {
    if (keyOrObj && typeof keyOrObj === 'object') {
        noAssert = value;
        for (var ikey in keyOrObj)
            if (keyOrObj.hasOwnProperty(ikey) && typeof (value = keyOrObj[ikey]) !== 'undefined') {
                if (ikey == "RuntimeField") {   // added
                    continue;                   // added    
                }                               // added
                this.$set(ikey, value, noAssert);
            }
        return this;
    }
    ...
}

This is of course not very maintainable. Is there a better approach? The object hierarchy is rich and deep so I'd like to avoid approaches involving wholesale copying of 100s of fields to/from custom JS-side objects.

Thanks for any suggestions.

Upvotes: 3

Views: 871

Answers (1)

Fenton
Fenton

Reputation: 251072

I have created a short example for you. You can solve this problem using Object.defineProperty to add a non-enumerable property (this won't show up when you use for (var key in obj).

In the example below, the first property is enumerable (and will appear in the console window along with the name property). The second property is not enumerable, so it won't appear in the console window.

Using this technique, you could add properties that won't be picked up in your for loop.

var obj = {
    name: 'Steve'
};

Object.defineProperty(obj, 'first', {
  enumerable: true,
  value: 'example'
});

Object.defineProperty(obj, 'second', {
  enumerable: false,
  value: 'example'
});

for (var key in obj) {
    if (obj.hasOwnProperty(key) 
        && typeof (value = obj[key]) !== 'undefined') {

        console.log(key);   
    }
}

So to tie this back to your specific question, you could use...

Object.defineProperty(ReceivedObject, 'RuntimeField', {
  enumerable: false,
  value: new RuntimeField()
});

Upvotes: 2

Related Questions