Accessing components from external JavaScript

I saw your example on how to communicate with external scripts. Is there a way to create custom events apart from “loadingStarted” “loadingProgress” and “loadingFinished” which other systems on the website can listen to? E.g. I wanna click a button in needle and some div element on the website should change color.
Already tried something like this but does not seem to work.

    public activateOverlay(_overlayID : string = "")
    {
        console.log("Func fired");
        this.context.domElement.dispatchEvent(new CustomEvent("activateOverlay", {
            detail: {
                id: _overlayID
            }
        }));
    }

index.html

<needle-engine myFunction="activateOverlay"></needle-engine>
  <script>
    function myFunction(id) { 

      console.log("I'm alive!"); 
    }
  </script>

Original Post on Discord

by user 334342083445784576

You dont need to subscribe to it via the html element.
Multiple options:

Make your event static / your type accessible statically

export class MyComponent extends Behaviour {

static get Instance() { return this._instance }
static _instance? : MyComponent;

awake() { MyComponent._instance = this; }

and then import it in your script (make sure its a module)

import { MyComponent } from "your/package"

Alternatively get the context from the engine-element (see docs)

and then query for the component you are interested in:

async function init() {
  const ctx = await engine_component.getContext();
  const myComponentInstances = GameObject.findObjectsOfType(MyComponent, ctx)
// do what you need

Hmm, calling the “activateOverlay” function in the needle script from the external script works (line 12), but when I’m calling “activateOverlay” from the UnityButton, “onOverlayActivated” is not defined. I’m missing something.

by user 334342083445784576

Not sure what you sent there - can you copy the code here?

I assuem its a bind issue

Javascript :slightly_smiling_face:

Sorry, had to figure out how to format here. Now It’s looking readable :smile:
Needle Script

import { Behaviour, serializable } from "@needle-tools/engine";

export class NeedleActivateOverlay extends Behaviour {
    public onOverlayActivated?: (string) => void
    
    public activateOverlay(_overlayID : string = "")
    {
        console.log("Regt mich auf!");
            if (!this.onOverlayActivated) 
            {
                console.log("onOverlayActivated not defined");
                return
            }
             this.onOverlayActivated(_overlayID);
    }
}

external Script

import { GameObject } from "@needle-tools/engine";
import { NeedleActivateOverlay } from "./scripts/NeedleActivateOverlay";

const ctx = await document.querySelector("needle-engine")?.getContext()
const myComponentInstance = GameObject.findObjectOfType(NeedleActivateOverlay, ctx)
myComponentInstance.onOverlayActivated = MyCustomFunction;

function MyCustomFunction(id : string) {
    console.log("Es hat geklappt " + id);
}

myComponentInstance?.activateOverlay("Test");

by user 334342083445784576

the last line in the external script works, but pressing a button with this function is not

by user 334342083445784576

what does it print

“Es hat geklappt Test”
Pressing the Unity Button, it prints
“onOverlayActivated not defined”

by user 334342083445784576

What does it print when you log console.log(this) in activateOverlay

okay sorry for bothering.
I just found out there are multiple instances of this script in my scene :wink:

by user 334342083445784576

Works like a charm now!

const myComponentInstances = GameObject.findObjectsOfType(NeedleActivateOverlay, ctx)
for (let i = 0; i < myComponentInstances.length; i++) {
    myComponentInstances[i].onOverlayActivated = MyCustomFunction;
}
function MyCustomFunction(id : string) {
    console.log("Es hat geklappt " + id);
}

by user 334342083445784576

Javascript :slightly_smiling_face:

by user 334342083445784576