How to pass event to project script from expression in border binding

I would like to send the event.source.name from a ‘Text Area’ object to a project script to return a value for my tag. I tried adding ‘,event’ as the second argument to my runScript, but it does not like that.

The following code works, but I am just hardcoding the value to be returned to it. So I am almost there.

if(isNull(tag
("Investigations/" + {Root Container.Dropdown SelectID.selectedStringValue} + "/" + 
runScript("project.Expressions.shortName()")
+ "/number/number"))
,toBorder("line;black;1")
,if(tag
("Investigations/" + {Root Container.Dropdown SelectID.selectedStringValue} + "/" +
runScript("project.Expressions.shortName()")
+ "/number/number") > 0
,toBorder("line;red;1")
,toBorder("line;blue;1")
)
)

Bindings don’t have an event. With runScript, the closest you can get is to use a component custom method, giving you access to self. If you need more than that, you might find the objectScript() function helpful. From my free Simulation Aids module.

1 Like

Thanks. I now have another tool to use. I never used the custom methods before. Now I see lots of uses for it. One thing I don’t have a handle on, and that is performance and timing.

In the script above I replaced the project script with a custom method and it works fine. Then I decided I could make this more dynamic by passing the custom method to a more comprehensive project script and then back to it before using it in a border binding.

I started to get lags that made the technique unusable. But when I opened the border binding and saved it always switched immediately. I played with the runScript refresh rate but that did not seem to help. It looked like I may have overloaded the gateway.

What I have is working, but if you have insights into what happened I would be very interested to hear your explanation.

It’s really important that anything called directly from an event or from a runScript/objectScript binding run “instantly”. That is, no calls to a database or a tag lookup or anything else that would need a network round trip. Yeah, you’ll find a lot of examples on this forum that break that rule, and you can get away with it for some cases (like a button’s actionPerformed method–users expect a minor hesitation after clicking buttons). But in general, anything that requires more than a tiny fraction of a second to execute–in the worst case–needs to be placed on its own thread with system.util.invokeAsynchronous.

Tag bindings and query bindings are built to do their work in the background, and therefore do not hold up the GUI thread. Almost all scripting is kicked off on the GUI thread and needs to behave accordingly.

Entirely different (and complicated) considerations on the gateway. And gateway-ish rules for Perspective.

Project scripts: these are wonderful for two reasons:

  1. “Don’t Repeat Yourself”, aka “DRY”. Code that is used in multiple places can be defined and maintained in one place. You are responsible for carrying context from the call site into the functions via appropriate arguments. Pass self, or event.source in place of self, or the entire event object as function arguments. Calling a project script does not relieve you of the need to execute quickly, if called from the GUI thread.

  2. Project scripts can maintain state using dictionaries, lists, or object instances created at the module level during the initial startup of the script module. Subject to edits that force a script restart, but very handy if you need to cache information for quick access (supporting the timing requirements of the GUI thread).

One big gotcha: recursion.

Ignition’s property change scripts, events, and bindings are synchronous, on the GUI thread. That means that any assignment to a component property coming from a binding or a script will call the component’s propertyChange event right at that spot, pausing binding execution or the execution of an outer script that assigned to that property. This can cause recursion if any inner operation triggers another assignment to a property at an outer level–even if that assignment is the same value.