Search code examples
javascriptnode.jsv8node.js-addonnode.js-nan

How to pass a NEW Nan::ObjectWrap from C++ to Javascript?


I've defined the following wrapped class in my C++ Node extension.

class JSStatus : public Nan::ObjectWrap {
public:
    long statusCode;
    std::string statusMessage;
    std::string statusDetails;

    static NAN_MODULE_INIT(Init);
    static NAN_METHOD(New);
    static NAN_GETTER(HandleGetters);
    static NAN_SETTER(HandleSetters);
    static Nan::Persistent<v8::FunctionTemplate> constructor;
};

The normal calling sequence goes like this (all on the Javascript thread):

  1. Javascript calls MyExtension::UpdateStatus(callbackFunction)
  2. UpdateStatus() saves 'callbackFunction' for later use by SetStatus()
  3. UpdateStatus() calls a native library which returns status to a known, named method called SetStatus(NativeStatus)
  4. SetStatus() creates a 'JSStatus', copying values from nativeStatus
  5. SetStatus() passes the 'JSStatus' object to a known javascript function called StatusUpdated(JSStatus)

I'm stuck on #5, as there doesn't seem to be a way to "new" a Nan::ObjectWrap in C++, then pass that object to Javascript.

This seems like something that would be common enough to be covered by NAN, but I've been unable to ascertain how to do it. Any ideas?


Solution

  • It would appear there's no way to "new" an object in C++ and pass it to Javascript. My workaround was to create a generic JS object and add fields to it one at a time. Klunky, but not too difficult with NAN.

    // Send status to Javascript
    void sendStatus(JSStatus* status) {
        // Create callback parameters
        const int argc = 1;
        v8::Local<v8::Value> args[argc];
    
        // Create generic JS object for status
        v8::Local<v8::Object> jsObject = Nan::New<v8::Object>();
    
        // Create property names & values for each field
        v8::Local<v8::String> propName = Nan::New("statusCode").ToLocalChecked();
        v8::Local<v8::Value> propValue = Nan::New(status->statusCode);
    
        // Add field to JS object
        Nan::Set(jsObject, propName, propValue);
    
        // And again...
        propName = Nan::New("statusMessage").ToLocalChecked();
        propValue = Nan::New(status->statusMessage).ToLocalChecked();
        Nan::Set(jsObject, propName, propValue);
    
        // .... Etc., etc. for all the other fields ....
    
        // Set parameter to JS object
        args[0] = jsObject;
    
        // Pass status to Javascript
        v8::Local<v8::Value> jsReturnValue = jsStatusDelegate.Call(argc, args);
    }