J Tricks - Little JIRA Tricks
 
Scene 1:

Agile advocate in the room is screaming! How can you have 2 fix versions for a single ticket? How? How? How?

Several scenes (and days) later, Scene N:

Q: We need to restrict the fixVersion(s) field to have only one version. And we need it before the next meeting. Can you?

A: Yup, you are not the first one to ask. Let's do it!

Well, that was the plot! The fixVersion(s) field in JIRA allows multiple versions and this was one of the cases were the customer wanted to restrict the field to have only one version selected.

Doing this was pretty easy in the earlier versions of JIRA where it was a simple multiselect field. All you had to do was to find the appropriate velocity template that is used to render the field and make it a single select instead of multi select. The template was verions-edit.vm under /atlassian-jira/WEB-INF/classes/templates/jira/issue/field and that was it!

In JIRA 4.4.3, things are a bit more tricky. The fixVersion field is rendered using the same template but there is no multi-select field on the screen now. Well, there is one but it is hidden! Instead, the visible field is an Ajax field that populates the options as the user starts typing matching letters. And as the user selects one of the options, the multi select field takes that value. 

You can select more value, ofcourse! And that is what we wanted to restrict. 

The easy choice and perhaps the best (we will see why) is to do a Javascript validation on the submission of the form. Adding Javascript on a field is pretty easy in JIRA. All you need to do is to edit the field's description in the appropriate field configuration and add the Javascript there. This has an added advantage that the Javascript needs to be added only in the field configurations that you want and hence you can limit the restrictions for selected projects, all by simple configuration! That is why I said it is probably the best solution.

And Javascript validation can be done easily using AJS:

  1. Identify the fixVersion field
  2. Find out the nearest form. This is important because we don't want to hard code the create or edit form ids. Instead, this should work wherever the fixVersion field is added!
  3. Add the submit handler for the form and check the number of fixVersions selected
  4. Alert the user if the number of fixVersions is more than one!

Here is what I did:

<script >
  var formId = AJS.$("#fixVersions").closest('form').attr('id');
  AJS.$('#'+formId).submit(function() {
     var count = AJS.$("#fixVersions :selected").length;
     if (count > 1){
        alert('You can select only one Fix Version for an issue');
        return false;
     } else {
        return true;
     }
  });
</script>


And this is what happened when they selected multiple fix versions:


But, ah the buts, someone asked the question I was trying to avoid. Isn't this a reactive solution? Throwing an error when they submit the form, after they select multiple versions? Can we do something proactive? i.e. just prevent people from selecting it? 

Time to hack the AJS scripts that does the population of options.

Now, if you trace back from the class used in aui params in the versions-edit.vm, aui-field-versionspicker, you will find that initVersionPickers.js file uses it to create the selector picker. And the function used is AJS.MultiSelect. The AJS.MultiSelect function is declared in /atlassian-jira/includes/ajs/select/MultiSelect.js file. And that, is the file where I put my hack!

There might be different places where you can put the hack in but I found it appropriate to place it along side the duplicate check. There is a method _isItemPresent in the MultiSelect.js file which checks whether the option selected is already present or not! I have added few simple lines alongside it to check whether the list has atleast one version selected or not. And if it has, we are going to just alert the user and treat it just like the duplicate scenario. Here is the modified method:

_isItemPresent: function (descriptor) {
        //For fixVersions, return false if more than one version is selected!        
        var elementId  = this.options.element.attr('id');
        if (elementId == 'fixVersions' && this.lozengeGroup.items.length > 0){
        alert('You can select only one Fix Version for an issue');
        return true;
        }
        // Normal duplicate check
        var duplicate = false;
        var value = descriptor.value();
        
        AJS.$.each(this.lozengeGroup.items, function () {
            if (this.value === value) {
                duplicate = true;
                return false; // bail
            }
        });
        return duplicate;
},


And ofcourse, you should check if the field is fixVersions or not because the MutliSelect function is used by other fields like Affected Versions!

And that's it! When you try to select more than one version, user gets the alert then and there. The same alert, but well in advance!

Remember, the change has to be done in the minnified version of the javascript, MultiSelect-min.js as well. And yes, once this is done, it is applied system-wide. i.e. for all the projects. If you need this only for selected projects or you want to remove the checking for selected projects, add extra bits to check for projects. I would try to avoid that and use the first solution in that case.

PS: Don't forget to do this change for every upgrades of JIRA!

PS(2): Like this trick? Have a look at the book to see more!


Edit:  May 25, 2012

What if you are adopting the first method and you want to clear out all the fixVersions after the alert is shown? The following worked in response to Srinivas's query in the comments:

<script >
   var formId = AJS.$("#fixVersions").closest('form').attr('id');

   AJS.$('#'+formId).submit(function() {

       var count = AJS.$("#fixVersions :selected").length;

       if (count > 1){
          alert('You can select only one Fix Version for an issue');
          AJS.$("#fixVersions-multi-select").find('em').click();
          return false;
       } else {
          return true;
       }
   });
</script>


Here the line in bold clears the selected options by triggering a 'click' on the small close icon! - Tested only on 4.4.3.
 


Comments

12/12/2011 12:05pm

Neat. Other approaches I might try would be the Script Runner with a custom script, or even putting the JavaScript in a plugin to make the next upgrade easier. But that's useful JavaScript up there, thanks!

Reply
J-Tricks
12/12/2011 12:13pm

Thanks Matt.

Yes, it will be a good idea to put the script in a plugin of possible. Anything to make upgrades less painful :)

Reply
12/12/2011 12:30pm

It occurred to me that you might be able to use the change() function on the select element to avoid hacking the MultiSelect.js file.

Using this JavaScript in the Fix Versions description made the alert pop up for me. I'm not sure how to connect that to failing the form submission though, maybe do both?

<script>
AJS.$("select").change(function () {
if (AJS.$('#fixVersions option[selected="selected"]').length > 1) {
alert('You can select only one Fix Version for an issue');
}
});
</script>

Reply
J-Tricks
12/12/2011 1:04pm

Yup, The onChange function can alert the user but it isn't preventing the user from adding it. I did try it intially (though the script was slightly different). Maybe use both the alert and the form validation as you suggested.

If there was a way to find out the newly added fixVersion, we could have used jQuery to remove it from the select list!

Reply
mizan
01/20/2012 2:23am

Hi JTricks,
can we prepopulate Jira fields while creating an issue using the above method ? Can you please provide an example ? I want to prepopulate jira security level field based on user roles/group.

Thanx :)

Reply
J-Tricks
02/05/2012 7:42pm

Mizan,

Here is how I do it. There might be an easy way out there but this one surely is an option ;)

http://www.j-tricks.com/1/post/2012/02/some-ajs-tricks.html

Reply
Kapil
03/12/2012 5:21am

Hello J-Tricks,

Your trick of restricting Single Fixversion version worked for me using the second option of _isItemPresent: function (descriptor) .

Also i would like to restrict AffectsVersion to have a single value,please let me know the required changes to do so.

Thanks
Kapil

Reply
J-tricks
03/12/2012 6:02am

Glad it worked. Use 'versions' instead of 'fixVersions' to make it work for affected versions.

Reply
SRINIVAS
05/25/2012 12:23pm

If you are looking for both fix and affects version, this much easier way.

https://confluence.atlassian.com/display/JIRA044/Changing+the+Size+of+the+Fix+Versions+and+Affects+Versions+Select+List

Reply
J-Tricks
05/25/2012 2:59pm

Thanks Srini. But it doesn't work in the later versions as it not using tat template anymore.

SRINIVAS
05/25/2012 4:19pm

atlassian-jira-4.4.5-standalone/atlassian-jira/WEB-INF/classes/templates/jira/issue/field/versions-edit.vm is the exact file because i modified it and i am able to see the changes. Though i changed the class of the select box it is still showing the multiselect options. Don't understand why..

J-Tricks
05/25/2012 4:28pm

Yes, exactly. The multi select option is coming from Javascript elsewhere and not from that velocity template. It is the MultiSelect.js file.

SRINIVAS
05/25/2012 5:08pm

I wrote the onchange function and I am able to see the alert.. Can you tell me how to delete the option that is added?

function validateFixVersions(){
var count = AJS.$("#fixVersions :selected").length;
if (count > 1){
alert('You can select only one Fix Version for an issue');

}
}

J-Tricks
05/25/2012 5:48pm

This one will remove all the options selected:

<script type="text/javascript">
var formId = AJS.$("#fixVersions").closest('form').attr('id');

AJS.$('#'+formId).submit(function() {

var count = AJS.$("#fixVersions :selected").length;
if (count > 1){
alert('You can select only one Fix Version for an issue');
AJS.$("#fixVersions-multi-select").find('em').click();
return false;
} else {
return true;
}
});
</script>

Enjoy!

Srinivas
05/25/2012 6:05pm

Thanks Jobin!

This is removing all the selected options. Can we remove only one option from the selected list. Appreciate if you could mention some documentation related to the AJS functions.

J-Tricks
05/25/2012 8:17pm

You won't be able to do that with this approach. For that you will have to adopt the second method mentioned in the tutorial.

SRINIVAS
05/27/2012 1:25pm

In some browsers like firefox, the javascript alerts can be controlled by selecting the checkbox (Prevent this page from creating additional dialogs) in the alert. If we select that checkbox, it is not showing any more alerts and there by allowing to select multiple fix versions. Can you please tell me if there is a way to control that?

J-Tricks
05/27/2012 4:06pm

Nope. All JS Hacks are dependent on browsers allowing JS, alerts etc. There is nothing that can be done to override that.

Maybe, instead of an alert, you can add an error message by creating a div on the element and return false after that!

srinivas
05/29/2012 11:46am

The usage of div and span tags creating unnecessary textboxes above the fix version multi select box.

<div id="fix_version_error_message" style="display:none">$textutils.htmlEncode("You can select only one Fix Version for an issue")</div>

How to handle this? Please advise

SRINIVAS
05/29/2012 3:12pm

Yes i got it now. It is just a manipulation of div tags. I placed this div tag above the existing ones and finally solved this. Please let me know if there any way to clear only one fix version instead of clearing both.

I followed this approach because i tried to update the multi-select.js but it is not working. No clue about why this is not working though i followed all your steps in the second approach.

J-Tricks
05/29/2012 3:16pm

Cool. Regarding the second approach, see this bit in the post:

"Remember, the change has to be done in the minnified version of the javascript, MultiSelect-min.js as well."

Yissar
03/23/2012 4:43am

I am trying to copy the content of the Comments field into my own customfield - Comments1

Can you plesae tell me what is the javascript code for doing this?

Reply
Jorge
05/25/2012 11:58am

Hi there. I love your site and writing style!

I need some help coming up with a very similar JavaScript function that can work for Security Level. I need to enforce a certain security level for certain issue types.

This is what I have so far but it gives me NO errors or desired behavior. I'm even wondering if JavaScript is even running at all in the background.

<script >
var formId = AJS.$("security").closest('form').attr('id');
AJS.$('#'+formId).submit(function() {
var secval = AJS.$("security :selected").value;
if (secval <> 10004){
alert('Please select Security Level -> Other Users for DS Tickets!');
return false;
} else {
return true;
}
});
</script>

I don't mind the "reactive" approach for now because I'm running out of options... once I get the reactive approach nailed, I'll work on being more proactive about the setting of the status :)

Thanks for all your help.

Reply
J-Tricks
05/25/2012 4:13pm

Try this:

<script >
var formId = AJS.$("#security").closest('form').attr('id');
AJS.$('#'+formId).submit(function() {
if (AJS.$("#security").val() != "10004"){
alert('Please select Security Level -> Other Users for DS Tickets!');
return false;
} else {
return true;
}
});
</script>

Reply
06/08/2012 1:35pm

The irony is that there is a standard custom field type that allows only one Version. My problem is that my client wants a single component.

Reply
J-Tricks
06/08/2012 3:06pm

lol. Another hack :)

Reply
Royce
06/15/2012 12:53pm

I bought the book. Great stuff!

Questions: I am using JIRA 4.4.5.
How do I set a value in Affect Version/s field? I tried...

1. AJS.$("#versions-textarea").val("12345").click();
"12345" is the version id. This kindda works, but cause "No Matches" to show up initially in the drop-down and the field won't populate with the corresponding version name until I click another field on the screen.

2. AJS.$("#versions-textarea").val("My Version").click();
Using the name of the actual version caused the drop-down list to show with "My Version" highlighted, but not actually populating the field with the value, and clicking away to another field caused the drop-down to disappear and ended up with no value in the field.

In addition, how do I set multiple values in Affect Version/s field?

Thanks!

Reply
Royce
06/20/2012 3:27pm

My co-worker suggested:
AJS.$("#versions-textarea").val("1234").blur();
and that worked! So use .blur() instead of .click().

Reply
J-Tricks
06/20/2012 7:17pm

Awesome! Thanks for commenting here. I hope someone will find it useful.

Royce
01/16/2013 3:41pm

Well, the .blur() doesn't work in IE 8. :( Someone know a sure way?

Renu
10/17/2012 5:01am

Hi J-Tricks,

I want to make affects version & fix version as a single version picker in Jira 5.1.3.
The above script is not working for Jira 5.1.3. Can you please suggest me an option for the same?

Thanks in advance.
Renu

Reply
J-Tricks
10/17/2012 7:14pm

Which option did you try?

Reply
Renu
10/18/2012 3:37am

Hi J-Tricks,
Thanks for your reply.

I have modified following files :
1. install_dir>/atlassian-jira/includes/ajs/select/MultiSelect.js
2. <install_dir>/atlassian-jira/includes/ajs/select/MultiSelect-min.js

I have added following script for file MultiSelect.js

_isItemPresent: function (descriptor) {
//For Fix/AffectsVersions, return false if more than one version is selected!
var elementId = this.options.element.attr('id');
if ((elementId == 'versions'|| elementId=='fixVersions') && this.lozengeGroup.items.length > 0)
{
alert('You can select only one Fix/Affects Version for an issue');
return true;
}
// Normal duplicate check
var duplicate = false;
var value = descriptor.value();
AJS.$.each(this.lozengeGroup.items, function () {
if (this.value === value) {
duplicate = true;
return false; // bail
}
});
return duplicate;
},

& for file MultiSelect-min.js following script is added :
_isItemPresent:function(descriptor){var elementId=this.options.element.attr('id');if((elementId =='versions'||elementId=='fixVersions')&&this.lozengeGroup.items.length > 0){ alert('You can select only Fix/Affects Version for an issue');return true;}var duplicate=false;var value=descriptor.value();AJS.$.each(this.lozengeGroup.items,function(){if(this.value === value){duplicate = true;return false;}});return duplicate},

Previously, I was using Jira 4.3.2, In that above scripts are working properly but now I have upgraded my Jira to 5.1.3.

The above scripts are not working properly. I can select two & more afftects & fix versions though the above scripts are added.

Can you please tell me, How can I do this??

Thanks & Regards,
Renu

Nancy Belser
10/30/2012 11:42am

My solution to this problem may not please some of you, but for Jira 4.4.x, I replaced the entire versions-edit.vm with an edited 4.1.1 version (only edit being the removal of multi-select). My users do not get the benefit of the new type ahead control, but it was more important to implement single select. I just tested this with Jira 5.1.6 and it still works. I should note that any version-picker custom field would still use the newer multi-select control. Not sure how to deal with that yet.

Reply
Nancy Belser
10/30/2012 7:14pm

Just read Matt's comment about the single select version custom field. Duh!

Reply
J-Tricks
10/30/2012 7:57pm

One problem solved I guess? lol

Reply
nancy.belser
10/31/2012 5:44am

By the way, I love this site and your book! Thanks for the great work!

J-Tricks
10/31/2012 7:01pm

Thanks. No better feeling than knowing someone finds this useful!

Renu
10/31/2012 5:43am

Hi J-Tricks,

Can you please tell me, How to make affects version & Fix version single version picker in 5.1.3?

Thanks & Regards,
Renu

Reply
Renu
10/31/2012 11:18pm

Hi Jobin,

Sorry to bother you. Single Select affects & fix version scripts are working fine with 5.1.3.

Thanks & Regards,
Renu

Reply
J-Tricks
11/01/2012 5:35am

Oh, that's good to know. I was going to try it out this weekend. Thanks for updating :)

Reply
Srinivas
01/24/2013 2:06pm

Hi Renu,

Could you please let me know how you had achieved and have you tried the same in 5.2.2? If possible share the script code please..

Thanks,
Srinivas

Reply
Renu
11/04/2012 10:28pm

Hi Jobin,

Thanks a lot for the useful info.

Reply
Mizan
12/07/2012 3:57am

Hi Jtricks .

If i Archive a version which was a value in Fix Versions then I get an option to add another Version . How can I prevent this. I cannot have 2 fix versions in any case but for archived version i get an option to add one more version as a fix version ...
Please help

Reply
Mizan
01/07/2013 2:32am

I found a workaround for this . I hide the complete field if the Archive version is present. Like this my fix version cannot contain 2 versions :)

<script type="text/javascript">
AJS.$(function(){
AJS.$('label').each(function(){
if(AJS.$(this).html() =='Archived Fix Version/s')
{
AJS.$('label[for="fixVersions"]').parent().hide();
}
})
})
</script>

Reply
Srinivas
01/16/2013 2:14pm

The below statement seems not working in JIRA 5.2.2.
AJS.$("#fixVersions-multi-select").find('em').click();





Reply
Royce
01/16/2013 3:57pm

Ha, probably Atlassian changed the UI/libraries again.

Reply
01/16/2013 5:52pm

Could you please let me know if there is any other way that can be used to clear the options from the fix versions multiselect component?

ckr
03/28/2013 4:38am

Hi jtricks!!
How can I automatically populate affect versions in sub-task by default from parent in create sub-task screen using javascript?

Reply
Raj
05/23/2013 9:56am

Jobin
above AJS script is not working for Component/s field in JIRA 5.1.8,
do you have simple java script which i can put in description of Component/s field to select only one component?.
Thanks

Reply
Tian
06/26/2013 10:26pm

The script seems not working in 5.2, can you check why. Thanks

Reply
Martin
12/03/2013 10:23am

Hi,
I think I am missing a step for making the change in MultiSelect.js as the change is not being picked up. I have restarted Jira - Is there something else I need to do?

Thanks,

MArtin.

Reply
J-Tricks
12/03/2013 3:18pm

Did you change in the minnified version of the javascript, MultiSelect-min.js?

Reply
Martin
12/04/2013 10:23am

Yes - I have just double checked. I am using Jira 5.0.6.

Reply
Lanthanide
03/06/2014 8:22pm

Now, can you do something similar for Labels?

We're getting ready to start using Jira in anger, and are anticipating many users adding labels such as "deg", "degerdation", "DEGRADATION" and "degadation" to issues, when the correct label to use is "degradation".

Is it possible to come up with a white-list of allowable labels, so that if someone has a typo or tries to create an unsanctioned label, they get an error like is shown here?

Reply
J-Tricks
03/06/2014 8:38pm

Frankly, I wouldn't recommend using labels for this purpose. Sounds more like a Select List field (with pre-defined options) but with the Ajax style of picking the values.

We created an "Ajax List" field for one of the customers for the same purpose. You might want to look at a similar solution.

Reply

Your comment will be posted after it is approved.


Leave a Reply


J tricks - Little JIRA Tricks