How to remove and add options to component selection via Javascript?

CL April 20, 2013

Hi,

does someone already have a javascript solution how to remove and add again components to be selectable?

My problem (tested with Jira 4.4):

I want to provide only part of the components in the projects to be available for selection depending on a custom field "client" (single select field).

I.e I have component1 .. component6, client A has only licensed component1 and component4, client B has licensed component1 .. component4. When I select the client, only the licensed components of the client shall be available for selection.

The selection of components seems to be a bit tricky - there is an id "components" (hidden) containing all options availabe including an attribute "selected". And there is a class "representation" which is showing the selected components only as buttons, with clicking the buttons will remove the according component from selection.

I am quite new to jacascript and jquery. What I managed to do:

I could remove the options from "components" and depending on the selected client I could add the according components in the html. I can see them in Firebug.

I am struggling with:

Removing the selected components from representation, i.e. the formerly selected components are still shown in "representation" when I changed the clients - that also happens, if I only remove the "selected" attribute of the components in id "components" (without removing components).

Second problem:

Even if no component is selected, if I remove the components and add only those for the new selected client the dropbox to select the components can not be used to show the available options. Firebug is showing an error "invalid descriptor" in "batch.js" which is probably a script from Jira.

My next step: try to find out more about the "invalid descriptor" error. However, if someone already has a solution to manipulate properly the selection of components - thanks for sharing.

Clemens

3 answers

1 accepted

1 vote
Answer accepted
CL May 2, 2013

Problem is solved now. Solution is based on answer of Jamie Echlin in this question https://answers.atlassian.com/questions/43534/can-i-have-multi-select-custom-field-behave-like-components-versions-fields (Thanks, Jamie).

She provides code to use a multi-select field in the same form as component select field. And that is what I used.

My code now:

<script type="text/javascript">
/* This script modifys the options available in components select field depending on values in another single select field
Tested with Jira 4.4 */

/* Definitions used in this script. Need to be adapted when used with other fields or options */
var controlling_fieldID="customfield_10200"; // Id of the field the options are depending on
var allowed_components = new Object(); // Object of arrays of allowed component option ids depending on the value in the controlling feed

/* VAL_1 .. VAL_4 are the possible values of the single select field,
10000 .. 10005 are the id of the available options for component selection */
allowed_components["VAL_1"]=new Array("10000", "10002", "10004");
allowed_components["VAL_2"]=new Array("10001", "10003", "10005");
allowed_components["VAL_3"]=new Array("10000", "10005");
allowed_components["VAL_4"]=new Array("10000", "10001", "10002", "10003", "10004");

/* Object to store the initially existing options */
var allComponents = new Object();

/* initialise the script; execute once when document is ready */
AJS.$(document).ready(function() {

/* store all initial options */
AJS.$("#components option").each(function (index) {
/* you might consider to store the option objects itselves, rather than storing the individual data per option */
id = (this).value;
var oneComponent = new Object();
oneComponent["id"] = id;
oneComponent["title"] = (this).title;
oneComponent["text"] = (this).text;
allComponents[id] = oneComponent;
});

/* Set onchange function for customfield controlling_field
with that the script will modify the allowed component options each ti,e the value of controlling_field will change */
var controlling_field =document.getElementById(controlling_fieldID);
if (controlling_field) {
controlling_field.onchange = controlling_field_changed;
}

})

/* This function will be executed each time the value in field controlling_field changes */
function controlling_field_changed() {

/* deselect currently selected component options in the component representation
this should not really be necessary, as the complete object containing this selection will be removed later
but I like the approach of "rolling back" what has been done before */
AJS.$("#components-multi-select .representation ul.items em").click();

/* remove currently valid options from #components */
AJS.$("#components option").remove();
AJS.$("#components").attr("size", "-1");

/* Set new valid options for #components */
/* pick the array of option ids depending on the selected value in the controlling field */
componentArray = allowed_components[AJS.$("#"+controlling_fieldID+" option:selected").text()]; // if controlling field is not a single select, this will need to be adapted
if (componentArray != null) {
for (i=0; i<componentArray.length; i++) {
component = allComponents[componentArray[i]];
/* build the new option element */
AJS.$("<option/>").val(component.id).attr("title",component.title).text(" "+component.text+" ").appendTo("#components");
}
/* Set correct size of options in #components */
AJS.$("#components").attr("size",String(componentArray.length-1));
}

/* remove existing multi-select-field of components */
AJS.$("#components-multi-select").remove();

/* Create new multi-select-field for components
this also fills the drop-down-list of options with the options defined above for #components */
(function($){
new AJS.MultiSelect({
element: $("#components"),
itemAttrDisplayed: "label",
errorMessage: AJS.params.multiselectComponentsError
});
})(AJS.$);

}

</script>

Of course, there is still room for improvements, but for my purpose it works.

Clemens

0 votes
Hung Nguyen February 17, 2015

Clemens,

Could you resolve this at last? I got the same error but could not figure out how to fix it.

Thanks

Hung

0 votes
CL April 27, 2013

Ok - some update here:
The first problem (removing selected components) I could solve.
Code:

AJS.$("#components-multi-select .representation ul.items em").each(function(){
this.click();
})
/* I know, can be shorter ... :-) */

My second problem has changed a bit:
With the code above I have deselected the formerly selected options. Now still all options are available for selection.

How can I reduce the list of available selection? Removing all options from #components and adding the "allowed components" results in a problem as described above:

Error message in Firebug:
TypeError: descriptor is undefined
[Bei diesem Fehler anhalten]

var descriptorVal = descriptor.value().toLowerCase();

batch.js (Zeile 29224

I tried to find to disable options in #components (instead of removing) - but did not find a way for that.

Other approach was:
In the dropdown list the items have a attribute "hidden" - but setting this to "true" did not exclude the item from the shown list.

Any ideas?

Clemens

Suggest an answer

Log in or Sign up to answer