Forum Discussion

Exo_Guid's avatar
Exo_Guid
Partner
9 months ago

UI Button with sendCodeblockEvent

Hello!

I'm editing a script in which my UI buttons should send an event with parameter to a target object containing a codeblock script.  Everything is setup and will print to the debug log but I'm having an issue constructing the send event code:

type GenericDialogProps = {}

function pickoption0(this: any): void {
  console.log("option1");
  this.sendCodeBlockEvent(this.props.target, new CodeBlockEvent<[index: number]>('GetOption',[PropTypes.Number]), "0")
}
function pickoption1(): void {
  console.log("option1");
}
function pickoption2(): void {
  console.log("option2");
}
function pickoption3(): void {
  console.log("option3");
}
function pickoption4(): void {
  console.log("option4");
}
class UItemplate extends UIComponent<GenericDialogProps> {
  static propsDefinition = {
    target: {type: PropTypes.Entity},
    index: {type: PropTypes.Number},

 

I receive the error:

Error Handling Event:
TypeError: Cannot read properties of undefined (reading 'sendCodeBlockEvent')
at pickoption0 (UItemplate.ts:152:7)
at option0 (UItemplate.ts:183:12)
at horizon/ui/HorizonUI.ts:1875:12

7 Replies

  • I suspect that you forgot to wire 'target' in your property panel to another entity?  Surprised that that actually compiles w/o errors, as `this.props.target` can be `undefined`

    • Exo_Guid's avatar
      Exo_Guid
      Partner

      Thanks for the reply.  The target is linked to the appropriate object running the codeblock script. 

      I've attempted a couple variations of the this.props.target and no errors show up until I hit the button.  Would it help if I posted the entire script?

  • this.sendCodeBlockEvent() can only be called from within a Component, not a normal function. "this" is a keyword that is a reference to the object that is currently block-scoped. Instead of "this: any" in your parameters, use "entity: Entity" and call "entity.sendCodeBlockEvent()" within that function.

    • Shards632's avatar
      Shards632
      Mentor

      Ah, yes.  Didn't notice that. The 'this' is definitely `undefined` here unless you are doing a binding to the function's `this` at the call point.  Also, never use `any` for a type.

    • Exo_Guid's avatar
      Exo_Guid
      Partner

      Thanks for the help.  I'm very new to TS but I'm slowly learning.

      I'm not sure if I've made the changes correctly as I'm getting errors.  I've included the part of the code where the UI is calling the function. 

      Should I remove the functions and move the sendCodeblockEvents directly under the buttons "option0: ()"?

       

      • PigeonNo12's avatar
        PigeonNo12
        Partner

        The errors are due to scope and undefined parameters.

        • Scope: The functions defined between lines 150-165 are outside the class scope (line 166). If you are planning to send events from those functions, your best bet is to move those inside the class. After doing this, delete the "function" keyword, and replace "entity.sendCodeBlockEvent" with "this.sendCodeBlockEvent". There are other ways, but this recommendation is the safest way since you are just starting with TS.
        • Undefined Parameters: the function called pickoption0 requires parameters, as defined in line 150 (it's expecting to receive an entity when called). To fix this, either remove the entity as a parameter of the function or pass an entity as an input when you use it in line 183.

        By the way, if you move the functions inside the class, you will need to call them with "this." like this.pickoption1().

  • Thanks everyone!  Really appreciate it!  I moved the events down and removed the functions.

    class UItemplate extends UIComponent<{ target: Entity; type: number }> {
      index: number = 0; // Define the index property as a number
      static propsDefinition = {
        target: {type: PropTypes.Entity},
        
      };
    
    
      initializeUI() {
        return View({
          children: [
            MyPrompt({
              promptLabel: "Pick Option",
    
              option0: () => {
                this.index = 0;
                this.sendCodeBlockEvent(this.props.target, new CodeBlockEvent('GetOption',[PropTypes.Number]), this.index);
              },
              option1: () => {
                this.index = 1;
                this.sendCodeBlockEvent(this.props.target, new CodeBlockEvent('GetOption',[PropTypes.Number]), this.index);
              },
              option2: () => {
                this.index = 2;
                this.sendCodeBlockEvent(this.props.target, new CodeBlockEvent('GetOption',[PropTypes.Number]), this.index);
              },
              option3: () => {
                this.index = 3;
                this.sendCodeBlockEvent(this.props.target, new CodeBlockEvent('GetOption',[PropTypes.Number]), this.index);
              },
              option4: () => {
                this.index = 4;
                this.sendCodeBlockEvent(this.props.target, new CodeBlockEvent('GetOption',[PropTypes.Number]), this.index);
              },
            }),
          ],