Skip to content

JQuery and Other External Libraries v7

Stefano Balietti edited this page Oct 21, 2021 · 2 revisions
  • status: complete
  • version: 7.x

Overview

If you need to integrate an external library in your game, like JQuery, you need to understand how frames are loaded.

nodeGame loads every new page in a dedicated iframe. To keep the connection with the server alive during page loads, the node instance lives at a higher level, outside of the iframe. This means that libraries loaded inside the iframe are normally not immediately accessible from the player.js client type. Likewise, the node object (as well as other libraries loaded outside of the iframe) is not immediately accessible from scripts loaded inside the frame.

Accessing node from inside the frame

From any script loaded with the "<script>" in the iframe, you can access objects in the parent page using the parent keyword.

<script>
window.onload = function() {
    // Load main nodeGame libraries.
    var node = parent.node;
    var W = parent.W;
    var J = parent.J;
};
</script>

Accessing libraries loaded in a frame from parent window

Two solutions are available.

Solution 1: Use the event/emit pattern in nodeGame

Inside the iframe:

<script>
window.onload = function() {
    var node = parent.node;
    node.on('mySettings', function(settings) {
        // Here jQuery or other library code.
    });
};
</script>

Inside your player.js file:

node.emit('mySettings', { foo: 'bar' });

Comment: with node.emit, you exchange local information, for instance from the player.js to the script in the html page (and vice versa); with node.say you exchange remote information, for instance from the logic to a remote player.

Beware of caching

node.on creates an event listener that is bound to the step in which it is created (for details see the Event Listeners page).

If the same HTML page is shared across multiple steps or repeated across rounds, it may get cached by the HTTP server or the browser. If the page is cached, the script inside the page may not be reloaded at each new step, and therefore the event listener will not be added again.

To avoid this problem, you can register the event listener on a higher level. Instead of node.on(...) you use node.events.stage.on(...), and it will stay active for all the steps of the same stage.

Now you just need to pay attention that, in case the page is reloaded in some browser, the listener is not added twice. See the code snippet below:

<script>
window.onload = function() {
    var node = parent.node;

    // If the page is cached, we exit here
    // to not add the event-listener twice.
    if ('undefined' !== typeof window.mySettingsCb) return;

    window.mySettingsCb = function(settings) {
        // Local code.
    };

    // This event listener is registered at a higher level,
    // and will stay active for all the steps in the same stage.
    node.events.stage.on('mySettings', window.mySettingsCb);
}
</script>

Solution 2: Access the iframe's window

If the functions you need to access are defined as properties of the window object of the iframe (as in the code snippet at the end of Solution 1), you can invoke them directly from player.js.

// Get the frame window.
var frameWindow = W.getFrameWindow();
// Execute the function triggering jQuery code
// (you may also trigger jQuery directly).
frameWindow.mySettingsCb(...);

Loading Libraries at the Parent Level

If your game makes extensive usage of an external library, it might be best to load it from the index.htm file of the public/ folder. In this way, it will be available to all frames of the game without reloading it.

Consider the following example for jQuery.

Inside the iframe, you can access jQuery loading in the parent window using the parent keyword.

<script>
window.onload = function() {
    // Load jQuery.
    var $ = parent.$;
};
</script>

In the parent window (for instance, in player.js) you will be able to access jQuery directly. You may create new elements and popups, but you will not have direct access to the iframe elements. For this you need to use the contents method.

// To locate a div with ID "instructions".
var doc = W.getFrameDocument();
$(doc).contents().find('#instructions');

More details in the jQuery doc.

Clone this wiki locally