Search code examples
javascriptjqueryiframeros

Initialize JavaScript object as global object for then use in Iframe


I have a class which required to be init.

class ROS {
  static init() {
    // do ros initialization
    ROS.ros = new ROSLIB.Ros({
            url: 'ws://' + ROS.host + ':' + ROS.ws_port.toString()
        });
    // and so on
    }
  static topic_publisher(topic_name, msg){
    var topic = new ROSLIB.Topic({
            ros: ROS.ros,
            name: topic_name,
        });
        topic.publish(msg);
    }
}

If I want to publish a message to a topic (call the topic_publisher) I just need to do like this ROS.topic_publisher("x_param', '0.1').

However, in those respected page, there should be a script which already called ROS.init() (at least one from all scripts.js which I imported).

I design the web in which consist of 4 iframes and 1 parent. Let say all of them need to use ROS.topic_publisher("x_param', '0.1').

In the current design, I need to call ROS.init() across all page. It make the server to have 5 ROS clients.

I want to know, is there anyway for me to let the initialization once (in the parent maybe) and let the rest I frame only call ROS.topic_publisher("x_param', '0.1') without re-import or re-initialize the ROS.init().

I also try to use parent.object. So it is become like this:

On parent page:

var obj = ROS.init();
ROS.topic_publisher("x_param', '0.1'); // success

on Iframe page:

var obj = parent.obj;
obj.ROS.topic_publisher("x_param', '0.1'); // error 

Any information will be helpful... Thanks!


Solution

  • There are several issues. The first one is, AFAIK, unlike function, class does not create a global binding, so parent.ROS will not find anything. The second, minor one is that you would need to load ROSLIB in each window. Thirdly, init here is not really necessary, unless there is more to it — a simple static declaration should do.

    Something like this might work to alleviate all of them. (Note: the code is untested; I don't know what ROSLIB is)

    window.ROS = class ROS {
      static ROSLIB = top.ROSLIB;
      static ros = top.ROS?.ros ?? new this.ROSLIB.Ros(...);
    
      static topic_publisher(topic_name, msg) {
        const topic = new this.ROSLIB.Topic(...);
        topic.publish(msg);
      }
    }
    

    Note that all this only works if the origin of top is the same as that of child windows. If not, you would have to use postMessage instead.

    EDIT: Another idea is to not have ROS in each frame, but just the top one. (I believe this was the original concept that I misunderstood.) This is better, and only requires a tiny modification to the code:

    // only in top window
    window.ROS = class ROS {
      ...
    };
    ROS.init();
    

    Then you can use top.ROS.topic_publisher(...) in any of the windows.