Reputation: 72895
I've got a ProjectClient
class that contains a method (.GET()
) for making HTTP calls. It supports some arguments and a callback in the same manner as node-request, but has some complex url and header building functions that happens behind the scenes too:
client.GET(idOrDataObject, function(err, customResponse) {
// url is built based on the id or dataObject passed as the first param
})
On a successful response, one of the object types that comes back is a DataObject
:
client.GET(idOrDataObject, function(err, customResponse) {
console.log(customResponse.dataObject instanceof DataObject) // true
})
I'm adding a convenience method to the DataObject
class called reload()
that calls back to the client.GET()
method and reloads itself, but I'd like to be able to update this
with the new version of DataObject
that's returned from the server:
DataObject.prototype.reload = function() {
var args = Array.prototype.slice.call(arguments) // extracts all arguments
var client = helpers.client.validate(args) // ensures 'client' was passed in the args array before continuing
args.unshift(this) // prepends 'this' (the DataObject instance)
// How can I update 'this' with the response contained in the
// callback passed (the last element in 'args')?
return client.GET.apply(client, args)
}
Usage would look like this:
client.GET(idOrDataObject, function(err, customResponse) {
var o = customResponse.dataObject
// assume something changed on the server
o.reload(function(err, done) {
// o has now been updated with the latest copy from the server
})
})
Starting to think the only way this will work is if I hijack the callback further down the chain, e.g. inside client.GET
:
var DataObject = require('../lib/dataObject')
var request = require('request')
var _ = require('lodash')
var GET = function(client, args) {
var options = {
client: client
}
// if a preformatted options argument passed, assign it to options
if (_.isObject(args[0]) && !_.isFunction(args[0]) && args.length <= 2) {
_.assign(options, args[0])
}
options.callback = helpers.cb(_.last(args.filter(_.isFunction)))
options.type = _.first([options.type, args[0]._type, args[0]].filter(_.isString))
options.dataObject = _.first([options.dataObject, args[0]].filter(function(property) {
return (property instanceof DataObject)
}))
request('http://...', {
body: options.body,
json: true,
method: 'GET'
}, function(error, response) {
var customResponse = new CustomResponse(response)
if (options.dataObject instanceof DataObject) {
options.dataObject = customResponse.dataObject
// here I see both 'options.dataObject' and 'customResponse.dataObject' have the correct value for reloadTest
console.log('updated', options.dataObject.reloadTest, customResponse.dataObject.reloadTest)
}
options.callback(error, customResponse, customResponse.dataObject)
})
}
But even doing this, the original copy of dataObject
isn't being updated - it's as if it was cloned or duplicated and isn't a pointer to the original?
Here's a test that's proving the failure. How can I ensure that the correct pointer to dataObject
is passed?
var now = Date.now()
client.GET('test', function(err, getResponse) {
var dataObject = new DataObject(getResponse.dataObject)
getResponse.dataObject.reloadTest = now // 1452109996140
console.log('now', now, 'getResponse.dataObject.reloadTest', getResponse.dataObject.reloadTest)
// now 1452109996140 getResponse.dataObject.reloadTest 1452109996140
client.PUT(getResponse.dataObject, function(err, putResponse) {
// updated 1452109996140 1452109996140
console.log('putResponse.dataObject.reloadTest', putResponse.dataObject.reloadTest)
// putResponse.dataObject.reloadTest 1452109996140
dataObject.reload(function(err, response) {
// updated 1452109996140 1452109996140
console.log('done', dataObject.reloadTest, 'response.dataObject.reloadTest', response.dataObject.reloadTest)
// done 1452109916111 response.dataobject.reloadTest 1452109996140
})
})
})
Upvotes: 2
Views: 75
Reputation: 55678
The short answer is, you can't. You can't actually swap the object for another object. Some options:
Use a wrapper object, and give that the reload
method:
client.GET(idOrDataObject, function(err, customResponse) {
var o = new DataWrapper(customResponse);
o.dataObject; // old data
// assume something changed on the server
o.reload(function(err, done) {
o.dataObject; // new data
});
});
Update the data in the dataObject
, keeping the same object as before:
DataObject.prototype.reload = function(callback) {
client.GET(this, function(err, customResponse) {
// Assign all properties from the response to the existing obj
// Could also use $.extend, _.extend, etc
Object.assign(this, customResponse.dataObject);
callback(this);
}.bind(this));
}
Just pass the new object in the callback and ignore the old object:
DataObject.prototype.reload = function(callback) {
client.GET(this, function(err, customResponse) {
callback(customResponse.dataObject);
});
}
Upvotes: 1