Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Scriptrunner behaviours logic

Dirk Ronsmans
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
May 10, 2021

Hey everyone,

I'm struggling a bit to see how the logic of Scriptrunner behaviors triggers and processes the scripts.

I currently have one behavior linked to a JSM Request Type.

On this behavior I've added several fields and each field as it's own server side script.

Now I'm seeing some strange things happening and wanted to double check on whether my understanding of a behavior trigger and execution is correct.

When I change a field on my Request Type, will it always run thu all the fields I've added in that behavior and execute the script? 

Or do the fields that I add in the behavior mean that it will only trigger when that specific field is changed? I was always under the impression that a behavior will trigger when you change the field that is listed in that behavior and only for that field.

It's now that I'm seeing some weird things happening that lead me to believe otherwise.

Or maybe even clearer. It seems like when I hit my Create button to submit my request, the request is evaluated (errors on mandatory fields) and then all the behaviors seem to trigger.

I don't have any initialiser set but it almost seems like when the validation of the request is done (mandatory fields) that the form reloads and triggers all the behaviours as if all the fields I have defined are changed..?

 

Anybody got some thoughts?

1 answer

1 accepted

Suggest an answer

Log in or Sign up to answer
1 vote
Answer accepted
Peter-Dave Sheehan
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 10, 2021

You can use your chrome developer tool and examine all the network calls to rest/scriptrunner/behaviours/latest/validators.json  and rest/scriptrunner/behaviours/latest/runvalidator.json

Here is what I've deduced from that..

  • When you first access an issue or open a screen the validators.json api is called to get all the fields impacted by a validator base on behaviour mapping, all the server-side scripts will be executed. That means any initializer and any field server-side script. This is to get the initial state of each field.
  • Then as the fields that were found in the mapping are initialized (perhaps by default values in the initializer or by the issue value when editing) the runvalidator.json for each field is called.
  • As you make further manual changes, the runvalidator.json will continue to be called for just the fields that you change.

So the trick is, assume each server-side script will be run once with each time a screen is loaded. If you will react to changes, make sure the changes are real. For example, I have a behaviours that clears field A every time field B is edited. I don't want to have this script wipe field A each time I edit the issue and change other fields (but not B). So to protect against that, I check the value of field B against the underlyingIssue and if it's different, then I clear field A.

Something like this:

import com.atlassian.jira.component.CoponentAccessor
def fieldB = getFieldById(fieldChanged)
def fieldA = getFieldByName('fieldA')
def cfB = ComponentAccessor.customFieldManager.getCustomFieldObject(fieldB.fieldId)
if(underlyingIssue && fieldB.value != underlyingIssue.getCustomFieldValue(cfB)){
fieldA.setValue('')
}
Dirk Ronsmans
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
May 10, 2021

Hey @Peter-Dave Sheehan ,

Interesting findings and workaround. This does throw of how I've been thinking about behaviours in general. My broad idea/understanding was that 

  • the initializer would load when you open the screen (the first time)
  • any field scripts would only run when you (manually) changed that field.

Like you mention, any time a single field is changed, only the part for that field is executed. However, when a field is loaded/reloaded it will call the initalizer (makes sense when opening to me but not after) but also all the field scripts that are in your mapping.

Now in general that doesn't seem like much of an issue and I tend to not have an issue with it because I only use my behaviours for/map them to Request Types, to assist the customer, which doesn't interfere any more afterwards.

I only noticed the behaviour because indeed a field with a specific value cleared some other fields. Then I add data to those newly cleared field. Where it goes wrong then is that when I hit the create button and the mandatory fields are checked (from the request type) which in turn returns a "you missed a field", I guess it reloads the screen and runs both the initializer and all the scripts from the mapped fields causing my newly manually entered data to be cleared again.

The way your workaround then works is by double checking the front end value vs the underlying issue value and only executing the behaviour if this really changed. Nice idea!

 

I did reach out to Adaptavist for this as well to get a definitive answer (besides my best educated guess) and here is what they provided me.

I can confirm that all behaviours attached to fields will be triggered when you press the "Create" button. This is how Behaviour works in front end.

Fortunately, this problem can be easily worked around by using setError() and clearError(). To do that:
1. Add following snippet to field A:

getFieldByName("Field X").setError("You need to enter a value")getFieldByName("Field Y").setError("You need to enter a value")getFieldByName("Field Z").setError("You need to enter a value")

  1. Adding following snippet to fields X, Y and Z:

if (getFieldById(getFieldChanged()).getValue() == "") {  getFieldById(getFieldChanged()).setError("You need to enter a value")} else {  getFieldById(getFieldChanged()).clearError()}

Unless all three fields have value, the user can't press the "Create" button and, thus, won't trigger the field A behaviour to clear value.

 

essentially it seems it would make more sense then to handle the mandatory fields yourself in the code instead of having it handled by the request type mandatory flag and thus blocking the user from hitting the create button before all is filled in. 

TAGS
AUG Leaders

Atlassian Community Events