ScriptUI tip: decoupling components’ Event handling

Davide Barranca —  — 1 Comment

In a ScriptUI Window different components are usually registered for Events, and fire their own Handlers. You can build some interconnection, so for instance a Button’s ‘click’ handler triggers a change in a ListBox, which in turn reacts to its own ‘onChange’ Event. It’s quite easy to decouple this interaction, provided that you set up your code properly.


As a starting point, let’s write some basic demo code to build a Window with just a ListBox and a Button. The ListBox contains five children items, and the Button randomly selects one of them.

As it is the code now, I’ve set a button .onClick() function that makes the ListBox elements selection switch at random, and a ListBox .onChange() function just logging a message in the Console.

If you click few times the button, the ListBox elements selection changes: the super-simple flowchart is:

Coupled Events

and the Console will contain something like:

Mind you: when it happens, randomly, that the selected item is the same, the “ListBox onChange fired” message isn’t output because there’s no actual change in the ListBox itself.

While if you just manually select different items in the Listbox:

ListBox Event

This is what is logged then:

Say that, instead, you want the ListBox to respond to ‘change’ events only when you directly interact with it. That is, the Button will keep to change the selection, but it doesn’t have to trigger the ListBox handler anymore, this way:

Decoupled Events

That is to say, the two Events must be decoupled. In order to make things work this way you’ve to rewrite some code.

First, .onClick() and .onChange() don’t actually have any Event object available to the function (which may be handy), while .addEventListener() provides you with one.

Second, using .addEventListener() lets you specify a third argument, which is a Boolean that controls whether the handler responds only in the Capture Phase rather than the Bubbling Phase (for details about Events propagation see pag. 84 of the JavaScript Tools Guide CC). Default is false.

Bubbling is mostly used, as far as I understand, to diversify handlers in situations when, say, a container such as a Group has several Checkboxes in it. You can attach a handler to the Group, so that the click on every checkbox can “bubble” through it (and trigger a response), and attach a different handler on each checkbox, which fires its own peculiar function.

Here, I’ve been using the bubbling boolean to control the Event propagation, particularly:

That ‘true’ means, so to speak, that the 'change' event triggers the anonymous callback it’s associated with only when the user directly interact with the ListBox – i.e. selecting items. Conversely, the 'change' event in the ListBox caused by the Button function is ignored. And finally the Console logs only:

Update (and correction)

Apparently I’ve been either too lazy to check or completely drunk not to notice that the above example doesn’t entirely work. True, the Button click makes the ListBox selection change and doesn’t fires the 'change' event, yet when you manually click items in the list (i.e. change them) the list’s handler doesn’t fire either. Which is a problem, because the whole rationale of this post is about decoupling the events (and to kill one isn’t quite the right way to do it).

The workaround involves a deeper understanding of Events propagation. Quoting a short excerpt from the Documentation:

Capture phase — When an event occurs in an object hierarchy, it is captured by the topmost ancestor object at which a handler is registered (the window, for example). If no handler is registered for the topmost ancestor, ScriptUI looks for a handler for the next ancestor (the dialog, for example), on down through the hierarchy to the direct parent of actual target. When ScriptUI finds a handler registered for any ancestor of the target, it executes that handler then proceeds to the next phase.
At-target phase — ScriptUI calls any handlers that are registered with the actual target object.
Bubble phase — The event bubbles back out through the hierarchy; ScriptUI again looks for handlers registered for the event with ancestor objects, starting with the immediate parent, and working back up the hierarchy to the topmost ancestor. When ScriptUI finds a handler, it executes it and the event propagation is complete.

That said, I’ve worked around the problem nesting the ListBox in a Group (with its own handler):

The Group listens for 'click', (if you set the third argument to true, it will report the event phase as capture, otherwise as bubble), so it intercepts the clicks first and fires the handler, which can’t be triggered by the button. It works, but even if the ListBox doesn’t change (i.e. you click the same item that is already selected), it fires the handler anyway.


Print Friendly, PDF & Email

One response to ScriptUI tip: decoupling components’ Event handling

  1. Heya!
    Im currently working on a script for InDesign that a guy from adobe forums helped me out with. Unfortunally he wont respond to me anymore, so Im left with this exact problem you have here.

    The script is nearly completed, but Im not a coder and only gained some jsx-skills from customizing scripts-snippets. But I can dig deep in…but what he wrote, is a slick style of coding, and Im not any skilled with Events. So Im stuck with these events firing while I try to just get a listbox-selection back.

    If you want to help me out, please drop me a line.

    ps: just upfront what the script does: it throws a pallette with a listbox. the listbox contains the linkslist filtered by a string/array which must be found in the filepath to be valid. Upon click on listbox.item a functions are called to zoom onto that image, and select it. After that the linklist and the window is refreshed. But loosing the listbox selection in the process.
    I tried to store the previous listboxitem index, but setting it again fires up the OnChange-event from the listbox again, leading to a loop 🙁

Leave a Reply

Text formatting is available via select .

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">