Block component until event completion

Hello. I am trying to create a perspective component that fires a component event (eg. onActionPerformed) and waits for the full execution before allowing the user to fire another. The idea is for the user to not have the need to handle the state of the component. Is there a way to implement a functionality like this?

Yes,
but actually no,
but actually yes.

The simplest solution would to be to render your component differently (e.g. pointer-events: none) or similarly, or otherwise in the frontend stop firing events from your component. This is the first yes.

But, because browsers are running on the end user's machine, this can absolutely be circumvented or abused by sufficiently motivated people. Whether that matters to you is up to your environment - but if you're running in a typical desktop browser, be aware that any client side "security" is defeated as simply as by opening browser dev tools. This is the no.

The correct way to do this would be to lock out event processing on the gateway and the client. The client is informed it shouldn't send events, and outside of rare/malicious scenarios, it won't - but the gateway doesn't bother to trust this and locks out event submission itself anyways. This is the second yes.

This absolutely can be implemented with your own backend ComponentModel implementation. There isn't a lot of prior art on the state transitioning necessary, but it wouldn't be that hard to add your own.

However, this may not be a good idea at all. What is your intention with this component/what are you really trying to do? Maybe there's a better paradigm for the whole interaction in general.

1 Like

I am trying to create a component with a button that fires a custom component event onActionPerformed and sets the react component state as isExecuting = true. This variable isExecuting will prevent the components from firing more events but after the execution there is no easy way to set it to false.

Sure there is; from the backend (the ComponentModel implementation) you can fire an outgoing event:

Which you can then listen for in your frontend component:

And trigger whatever internal frontend component state update you need.

Can this method execute a user defined action:

Yes, from the frontend:

    @bind
    actionPerformed() {
        this.props.componentEvents.fireComponentEvent("onActionPerformed", {});
    }

Or the backend, via Component.fireEvent; the first parameter will be com.inductiveautomation.perspective.common.config.EventConfig.COMPONENT_EVENTS and the second parameter would be the name of the event.

I tried implementing following the Messenger example but couldn't make it work:



The log "Fired onActionPerformed" showed right after the "Received EventFiredMessage of type: start-action" and then it executed the action. How can I wait for the execution of the component to end so the log shows after the "Button 5 seconds" log?

I believe you'll need to run the code after this.component.fireEvent in the session queue this.component.getSession().queue()::submit.

1 Like

Tried it but didn't work. The gateway code still manages to run before the user code.


Going off memory here; I think the handleEvent is always queued?

So if you want in your function to run after the most recently queued event (i.e. your ‘fireEvent`), you’ll always want to submit to the back of the queue?

Sorry but I didn't understand your last message.

Tried to analise the ignition default component behaviour but its hard without proper documentation. Is there something that can help me understand how the communication/event handling in ignition works? I feel it will help me find a solution to my problem.

Trying changing from:

if(queue.isInQueue()) {
   func.run();
} else {
   queue.submit(func);
}

to simply:

queue.submit(func);

It'd be nice, but I don't know of any resources. FAFO + lots of logging :man_shrugging:.

2 Likes

This is what I needed on this cold Tuesday.

1 Like

Tried it but didn't work. Same behaviour: