How to call external JS function from Hype button

First of all, let me say I'm a Hype newbie (so far nearly a week), but a developer with many years experience in JS, PHP, etc etc.

I know this question must have been answered a million times, but I was unable to find it.

I have a Hype doc, and a button on stage.
I have included JQuery library and my custom external.js file in the resources.
Tested these and they work fine.

All I want to do is select the button and get it to call a function in external.js, passing the event as a parameter.

here's the function in external.js:

function test(event){
		console.log("button clicked");
}

To call this function I can't see a way of just adding test(event) to the button, as it seems that an internal function needs to be defined first.

so I do that with this internal Hype function:

        function hypeScript(hypeDocument, element, event){
        // call the function defined in external.js and pass it the event
        test(event);
        }

Unfortunately my console error is:
HYPE-728.full.min.js:141 Error in undefined: ReferenceError: test is not defined

I am therefore of the opinion that somewhere the scope of functions in the external.js needs to be declared, because built-in functions seem to still work (ie: console.log and alert() still work in the external file).

external.zip (77.2 KB)

Correct; if you want to call some JavaScript you need to first make a function.

The function is scoped inside of the jquery callback and is not global - you can verify this by opening the developer console and trying to type test() and will get the same basic error.

The easiest fix is to change your declaration to be an assignment on the global window object.

Instead of:

function test(event){

Use:

window.test = function (event) {

The alternative would be to not place the test() function inside the jquery ready callback.

Hope that helps!

OK so shifting the function definition outside of the ready callback works just fine, and is not too far outside my comfort zone to implement.
Based on that, I suppose that any global variable declarations need to be scoped in the same place - namely outside the JQuery ready handler.
I guess I'm curious because in many applications that I use, once JQuery is loaded and vars are declared within the ready handler, they are available globally.
I do find the logic of Hype's approach a little strange, but not unworkable.
It just means I'll have to recode a bunch of my libraries (and remember that they're Hype-only). Perhaps a new Repo is in order... ?
Thanks for the insight.

Thinking out loud here, I'm not comfortable with writing declarations outside the JQuery ready handler because of potential synchronicity issues, so the window assignment is a bearable kludge. But then there's a matter of all global vars, which would likely have to be dealt with in the same way??
Hmm. Perhaps I'm going to have to find a more elegant way to deal with this...

Trashing the windowObject is never a good idea :slight_smile:

Hypes Eventsystem includes HypeDocumentLoad. within the casllback you can store things to the HypedocumentScope.

external:

function HypeDocumentLoadCallback(hypeDocument, element, event) {

    hypeDocument.customFunctions = {
        'test': (arg) => {
            console.log(arg);
        }

    }

}

if ("HYPE_eventListeners" in window === false) { window.HYPE_eventListeners = Array(); }
window.HYPE_eventListeners.push({ "type": "HypeDocumentLoad", "callback": HypeDocumentLoadCallback });

if you don't like hypeDocument.customFunctions.test(arg) you can create your own namespace/scope and get sthg like thisIsMyTreasure.test(arg)

4 Likes

To clarify: your declaration is definitely not global; it can only be accessed within the $('document').ready() callback. Global in JavaScript is defined as being added to the top-level window object. Function definitions are done so only if they are declared in a top <script> scope or explicitly defined by setting a value on the window like window.test = function () { /* ... */};.

I'm guessing that in the past you setup all your other functions/closures in the $('document').ready() callback function? This would have given them access.

Are any of these open source/available to glance at? I might be able to better advise if I can see how you've organized it.

@h_classen's code dives a bit into this -- one thing to note is that Hype has its own loading infrastructure, and a Hype document will generally get loaded after DOMContentLoaded/the jQuery ready event. So you cannot use a jQuery ready to immediately start speaking to the Hype API.

Because of this, a lot of folks use the first On Scene Load event to run setup/initialization code. Alternatively listening for the HypeDocumentLoad event as @h_classen wrote is another approach, and perhaps if you want to expose some of your library code to Hype it could be done that way.

Hype is pretty vanilla in how it interacts with JavaScript; jQuery is really more the oddball :rofl:. (There are a few things it does to help shield its runtime from errors, encapsulate the document, and allow multiple identical animations on the same page, but this isn't really what you're encountering)

1 Like

OK Jonathan, you've given me plenty to think about here.
I think the obvious approach is to use a config called from the initial On Scene Load handler.
Not such a long stretch for me to repurpose.
And yes, my approach has been to run everything inside the .ready() callback.
Thanks you so much for taking the time to explain the architecture and basic methodology to me.
I'll now chew on that a while before I start taking up too much more of your time.
Much appreciated.

1 Like

just to mention:
a var within a hypefunction is scoped to this function of course.
so if you try to call a function or var that resists in another hypefunction it'll be undefined.

for a hypedocumentwide-variable it has to be a assigned to a key of hypeDocument or hypeDocument.customData

another idea to mention:
an eventdriven setup. you can setup your own or rely on Hypes customBehaviour as event.

very rudimentary setup:

your external functionFactory:

function HypeTriggerCustomBehavior(hypeDocument, element, event) {


    let [functionName, arg] = event.customBehaviorName.split(' | ');

    eval(`${functionName} ('${arg}')`);

    ////your factoryscripts below
    function test(arg) {
        console.log(arg);
    }



}

if ("HYPE_eventListeners" in window === false) { window.HYPE_eventListeners = Array(); }
window.HYPE_eventListeners.push({ "type": "HypeTriggerCustomBehavior", "callback": HypeTriggerCustomBehavior });

trigger within Hypefunction:
hypeDocument.triggerCustomBehaviorNamed('test | xyz');

this kind of setup seems to quite less work to adapt to your existing library

2 Likes

Thanks, Hans-Gerd.
I'm starting to get the hang of this now. After only working with the product for a week, I was getting frustrated with the scoping, as it didn't work in the way I was used to.
As a long-time Flash and Actionscript developer, the ability to use Classes, fully functional OOP etc suddenly died as Flash hit the trash and years of investment in those libraries went with it. :frowning:
Nonetheless, JQuery has been my go-to now and I'm looking for ways to implement my extensive libraries without having to rewrite just for Hype.

2 Likes