Waiting for JIRA triggers/events to finish before running custom javascript?

Seth Wingert November 15, 2017

I'm creating a Greasemonkey script to load default values for fields like "Sprint" and "Epic Link" when users create a new Issue. Currently users provide the desired text value, like "Bobs Sprint 3" and then the script is responsible for populating the field and backend HTML values.


I've had no problem with plain text fields, but the single-select and multi-select fields like "Sprint" are tricky since they AJAX load the <option> elements. I need to simulate clicking the Sprint field, wait for the JIRA AJAX options to load, then simulate clicking the proper select option. Is there some way I can hook into the AJAX events JIRA is running so I can wait for them to finish before running my triggers? Maybe through the underlying Deferreds? Here's what I've got, but the mousemove and click aren't working reliably due to the timing of GUI refreshes. I could add a setTimeout on each one but that seems really hacky:


//set raw value
AJS.$('#sprintId-field').val('Bobs Sprint 3');

//listen for the suggestions to refresh
AJS.$('#sprintId').on("suggestionsRefreshed", function(e) {
let $desiredLi = AJS.$('#sprintId-suggestions').find('li:contains(Bobs Sprint 3)');
//timing problems here!
$desiredLi.trigger('mousemove');
$desiredLi.trigger('click');
}

//trigger the suggestions load
AJS.$('#sprintId-field').trigger('click');

 

 

2 answers

1 accepted

0 votes
Answer accepted
Seth Wingert November 21, 2017

I solved it!  I ended up ditching the 'mousemove' and 'click' events as this was creating noticeable lag and weirdness in the GUI.  Instead I was able to get the JIRA backing objects for single-select and multi-select fields like "Sprint" and "Assignee" by listening to the "initialized" event.

//Listen for single-select and multi-select fields to initialize and put the Jira backing object as a "data" element on the field so can access it later.
AJS.$('#jira').on("initialized", function(e, jiraBackingObject) {
AJS.$(e.target).data('jiraBackingObject', jiraBackingObject);
});

Then later on I can make it retrieve the AJAX options by using the JIRA backing object.  No hardcoded REST URLs required!  Used promises here to account for async nature of REST queries.

let jiraObject = AJS.$('#sprintId').data("jiraBackingObject");
jiraObject.clearSelection(); //turns on 'aus-ss-edit' mode, which AJAX queries check before executing REST stuff
jiraObject.$field.val('Bobs Sprint 3'); //set text value to limit suggestions
return Promise.resolve(jiraObject.requestSuggestions()) //converts jQuery deferred to ES6 promise
.then(function (suggestions) {
jiraObject.$field.val(''); //clear text value since no longer needed for suggestions
//Some fields weirdly put the desired value at the end of array, so search backwards through the suggestions[] until we find value match
for (let i = suggestions.length - 1; i >= 0; i--) {
suggestions[i].properties.items.forEach(function (item) {
if (item.properties.value === 'idForBobsSprint3') {
//single-select
if (jiraObject.setSelection) {
jiraObject.setSelection(item);
} else { //multi-select
jiraObject.addItem(item);
}
return item;
}
});
}
});

 

0 votes
Alexey Matveev
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.
November 15, 2017

Hello,

What is exactly your dropdown? Could you get options for the dropdown from a rest api call?

Seth Wingert November 16, 2017

"Sprint" and "Epic Link" are the ones I'm working with now. I could do a rest call, but then how do I populate the dropdowns the correct Atlassian/JIRA way?  Before I was manually inserting <option> values but then JIRA was blowing up if the user tried to change them afterwards.  Apparently JIRA attaches jquery "data" attributes to each <option> but I couldnt figure out how to replicate that behavior.

Suggest an answer

Log in or Sign up to answer