
- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on ‎05-13-2021 12:44 PM
Do you need to require an additional field for Incident resolution but are not sure how to edit the Major Incident workbench Resolve button to account for this? If so, you are at the right place, and I hope this helps you!
**As a quick caveat, this does involve editing an OOB UI Page and at least some familiarity with editing or creating UI Pages in ServiceNow. This customization should also be monitored with each release to ensure you are consolidating code if new platform changes to the Major Incident Management plugin come out.
**NOTE: Please see the comments on this post for additional information on reference fields, dependent fields, etc
What is the issue we are trying to solve?
You have a custom field or existing field that is NOT used OOB for resolution in the Incident Management process....and you want to make this field required for resolution.
There is no issue with making this change in the Native UI & Agent Workspace as you can modify Client Scripts, UI Policies, and Business Rules easily to make sure the Native UI & Agent Workspace comply with your new requirement.....I am NOT going to cover that in this post.
However, there IS an issue if you use the Major Incident Management plugin as the Resolve button on the Major Incident Management workbench is a custom modal controlled by a UI Page and must be edited.
See the example below.
In this first image, you can see I added a custom field "Custom Resolution Code Field" and made it required for resolution via the the OOB UI Policy.
However, in this second image you can see in the Major Incident Mgmt Workbench, the Resolve action is managed separately, so we need a way to add this custom field.
How do we solve this?
We need to add the new field in the Resolve modal windows. Below are the steps to do it.
1. Locate the "mim_workbench_resolve" UI Page under System UI -> UI Pages. All work will take place here and in a custom script include we create
2. Add the field to the HTML (Client Side UI) code in the UI Page at the location you would like. In this case I am adding the below code in between the other two fields. I am highlighting where I make syntax changes that you will need to replace with your own field name or notation
<div class="form-group" id="resolution-custom-field-wrapper">
<label class="col-sm-2 control-label" for="mim-resolution-custom-field">
<span mandatory="true" class="required-marker label_description"><span class="sr-only">${gs.getMessage('required')}</span></span> ${gs.getMessage('Resolution custom field')}
</label>
<div class="col-sm-4">
<select id="mim-resolution-custom-field" required="true" class="form-control" onchange="resolveModal.resolutionCustomFieldOnChange()"><option value="">-- ${gs.getMessage("None")} --</option></select>
</div>
</div>
3. Add the following pieces of code to the UI Page Client Script. I am adding an explanation of each piece of code
//Not in a specific function - part of the initial variable definition (copy of lines 4-5)
//Allows the client script to detect the new field for further use later on in the script
A
var resolutionCustomField = $("mim-resolution-custom-field");
var resolutionCustomFieldWrapper = $("resolution-custom-field-wrapper");
//New function that will function on change of the new field (copy of 'resolutionCodeOnChange' function)
B
function resolutionCustomFieldOnChange() {
if(!resolutionCustomField.value)
resolutionCustomFieldWrapper.removeClassName('is-filled');
else
resolutionCustomFieldWrapper.addClassName('is-filled');
enableResolveBtn();
}
//Editing the 'enableResolveBtn' function so the Resolve button is enabled once all of the fields are filled in
//The only code being changed here is the first IF statement (highlighting the additional code)
C
function enableResolveBtn(){
if(resolutionNotes.value.trim() && resolutionCode.value && resolutionCustomField.value) {
resolveBtn.removeClassName('disabled');
resolveBtn.writeAttribute('aria-disabled', false);
} else {
resolveBtn.addClassName('disabled');
resolveBtn.writeAttribute('aria-disabled', true);
}
}
//Editing the 'resolve' function so the new field value gets saved to the Incident record
//Highlighting the added code - you should insert the name of your custom field
D
function resolve() {
if (!resolveBtn.hasClassName('disabled')) {
var record = {};
record.close_notes = resolutionNotes.value.trim();
record.close_code = resolutionCode.value;
//CUSTOM Code Start
record.u_custom_resolution_code_field = resolutionCustomField.value;
//CUSTOM Code End
_resolveRestCall(record).then(function() {
dialog.setPreference('reload', true);
close();
});
}
}
//Editing the 'global.resolveModal' to include define the new functions we created. Highlighting added code
E
global.resolveModal = {
resolve: resolve,
close: close,
resolutionNotesOnChange: _debounce(resolutionNotesOnChange, 200), // Only execute when left idle for 200 ms
resolutionCodeOnChange: resolutionCodeOnChange,
//CUSTOM Code:
resolutionCustomFieldOnChange: resolutionCustomFieldOnChange
//CUSTOM Code End
};
//NOTE: Only follow this next step if your field is a choice field. If this was a string field, you are good to go
//IF your new field is a choice field, you must create a script include (which will be shown in Step 4) and a GlideAjax call in this Client script (shown below) to retrieve those choice values
//The GlideAjax call will retrieve the choice values and populate them into your custom field
F
var ga = new GlideAjax('insertScriptIncludeNameHere');
ga.addParam('sysparm_name', 'insertScriptIncludeFunctionNameHere');
ga.getXML(callbackFunction);
function callbackFunction(response) {
var answer = response.responseXML.documentElement.getAttribute("answer");
var codes = JSON.parse(answer);
codes.forEach(function(item) {
resolutionCustomField.insert(new Element('option', {
value: item.value.value }).update(item.label.value)); });
}
4. Create a Script Include to work with your GlideAjax call in the previous step. Your script include name and function name must your calls in the GlideAjax script.
NOTE: Only follow this step if your field is a choice field. If this was a string field, you are already good to go
NOTE: Ensure this script include is created in the Major Incident Management SCOPE
//Below is the function code along with a screen shot of the entire Script Include. Make sure it is "Client callable"
insertScriptIncludeFunctionNameHere: function() {
var choiceRec = new GlideRecord('sys_choice');
choiceRec.addEncodedQuery('element=u_custom_resolution_code_field^name=incident');
choiceRec.query();
var returnArr = [];
while (choiceRec.next()) {
var itemObj = {};
itemObj.type = choiceRec.getValue('element');
itemObj.value = {value: choiceRec.getValue('value')};
itemObj.label = {value: choiceRec.getValue('label')};
returnArr.push(itemObj);
}
return JSON.stringify(returnArr);
},
Congratulations, you're done! The Resolve button in the Major Incident Management workbench should now include your new field and function properly.
- 5,516 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
My Instance has issue of Resolve UI Action. Resolve Button's Popup not showing on Form as well as On Workbench when I Click on Resolve Button.
Did you know any solution related to this?

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Akkihat,
Unless you have customized your instance, there is no Resolve button popup on the Native UI form.
For the Major Incident Management workbench, if you have NOT made code changes on the resolve or workbench UI pages, then this would be a system bug and you would need to submit a ticket to ServiceNow through the HI Portal. If you DID make code changes to any of the UI pages in the Major Incident Management module then it may be an issue with that code that you would need to troubleshoot.
Hopefully that helps.
Thanks,
Sasha
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Sasha,
So, I have a similar requirement to modify and add fields to "mim_workbench_resolve" UI Page , but I have been trying to add a reference field by using following code ,but it works fine in the "Try it" of ui page but on actual workbench view when I click the "resolve" button and the ui page pops up, whenever I try to Click the magnifying glass for the reference field it doesn't open up the referred table , rather the field acts like a string field instead of a reference type.
<div class="form-group" id="incSolving-activity-wrapper">
<label class="control-label col-sm-2" for="mim-incSolving-activity">
<span class="label-text">${gs.getMessage('Incident Solving Activity')}</span>
</label>
<div class="col-xs-12 col-md-8 form-field">
<g:ui_reference alt="Incident Solving Activity"
name="budget_code"
id="budget_code"
table="u_budget_code"
order_by="u_name"
value=""
query=""
displayvalue=""/>
</div>
</div>
PFA the screenshots of the different view's, as help me out here!

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi, unfortunately that g:ui_reference tag does not work in the workbench UI. That would only work if you were using it in a UI page for a modal in the native UI.
If you do not have a lot of records in the reference table, you could use the exact same method we are using for the choice field in the article above. You can create another field using the same "select" tag we used for the choice field and populate it with the reference table values instead of a choice field values. See below for a brief example.....you would also need to replicate the onChange functions and all other steps for this new field.
The reason I mention the # of records in the table is I am sure the page responsiveness would slow down if it tried to load thousands of choice values.
- Similar tag w/ a different ID
<select id="mim-reference-field" required="true" class="form-control" onchange="resolveModal.referenceFieldOnChange()"><option value="">-- ${gs.getMessage("None")} --</option></select>
- In the client script, get the field
var referenceField= $("mim-reference-field");
- Create another function in your script include
insertScriptIncludeFunctionNameHereTwo: function() {
var gr= new GlideRecord('INSERT YOUR TABLE');
gr.addEncodedQuery('INSERT YOUR QUERY');
gr.query();
var returnArr = [];
while (gr.next()) {
var itemObj = {};
itemObj.value = {value: gr.getValue('value')};
itemObj.label = {value: gr.getValue('label')};
returnArr.push(itemObj);
}
return JSON.stringify(returnArr);
},
- Create a new GlideAjax call in the UI Page client script
var ga2 = new GlideAjax('insertScriptIncludeNameHere');
ga2.addParam('sysparm_name', 'insertScriptIncludeFunctionNameHereTwo');
ga2.getXML(callbackFunction2);
function callbackFunction2(response) {
var answer = response.responseXML.documentElement.getAttribute("answer");
var codes = JSON.parse(answer);
codes.forEach(function(item) {
referenceField.insert(new Element('option', {
value: item.value.value
}).update(item.label.value));
});
}
- Create the other components like the onChange function and adding this function the resolveModal....see the article above for this
Hopefully that helps! Let me know how it goes!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Sasha,
g:ui_reference does work on the mim_workbench_resolve UI Page, you just need to uncomment the g:requires statements at the top of the Jelly code. There is a note in the comment explaining this (although I spent half an hour trying other things before I noticed the comment).
Your article was very helpful to me, and I was able to add four fields to the UI Page, including one reference field. (The "Caused by Change" reference field is displayed conditionally based on the value of the "Was this caused by a change?" question.)

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Tony,
Nice catch on the g:ui_reference!! I can't believe it was at the top of the page the whole time. I will make sure and add that into the article.
Glad that it helped you out.
How were you able to conditionally display the "caused by change" field? Is there a "mandatory" tag similar to "is_filled" class?
Thanks,
Sasha
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
The mandatory setting is part of the first span in the label. Notice that it has "mandatory='true'" and has a class of "required-marker".
Another thing I did was check the Incident for existing values in the fields I was adding so that I could populate them. In the case of the reference, I had to pass back both the value and the display value and populate both of them. For the select boxes, you can't populate the value until after the options are loaded, so I had my Ajax script return the current values from the incident and the select box options at the same time. In the callback, I added the options to the select box before I set the value. I also had to deal with the fact that the second select box options are dependent on the value selected in the first select box...
Here is what the Jelly/HTML for the Yes/No and reference field would look like:
<div class="form-group" id="resolution-yes-no-wrapper">
<label class="col-sm-2 control-label" for="mim-resolution-yes-no">
<span mandatory="true" class="required-marker label_description"><span class="sr-only">${gs.getMessage('required')}</span></span> ${gs.getMessage('Require reference field?')}
</label>
<div class="col-sm-4">
<select id="mim-change-related" required="true" class="form-control" onchange="resolveModal.resolutionYesNoOnChange()">
<option value="">-- ${gs.getMessage("None")} --</option>
<option value="Yes">${gs.getMessage("Yes")}</option>
<option value="No">${gs.getMessage("No")}</option>
</select>
</div>
</div>
<div class="form-group hidden" id="u-reference-wrapper">
<label class="col-sm-2 control-label" for="u_reference">
<span mandatory="false" class="label_description" id="u-reference-mandatory"><span class="sr-only">${gs.getMessage('required')}</span></span> ${gs.getMessage('Reference field')}
</label>
<div class="col-sm-4">
<g:ui_reference name="u_reference" id="u_reference" table="sys_user" onchange="resolveModal.resolutionReferenceOnChange()"/>
</div>
</div>
I want to call out a few things:
- I added the "hidden" class on the "u-reference-wrapper" div
- I added the id "u-reference-mandatory" to the first span inside the label for "u_reference"
- I set "mandatory='false'" on the "u-reference-mandatory" span
- You could add a reference qualifier to the g:ui_reference using the query attribute
Here's some example code of what the GlideAjax call would look like for loading both the dependent select boxes and the reference field:
var resolutionSelect1 = $("mim-resolution-select-1");
var resolutionSelect1Wrapper = $("select-1-wrapper");
var resolutionSelect2 = $("mim-resolution-select-2");
var resolutionSelect2Wrapper = $("select-2-wrapper");
var resolutionReference = $("u_reference"); // I used the field name
var resolutionReferenceDisplay = $("sys_display.u_reference");
var resolutionReferenceWrapper = $("u-reference-wrapper");
var resolutionReferenceMandatory = $("u-reference-mandatory");
// Couldn't get the "i" button working, but here is how you would get it:
// var resolutionReferenceInfo = $("u_referenceLINKreplace");
// There are some needed libraries missing for it
var gaValues = new GlideAjax("MyMIMAjaxUtils");
gaValues.addParam("sysparm_name", "getInitialValues()");
gaValues.addParam("sysparm_sys_id", window.NOW.MAJOR_INCIDENT_WORKBENCH.sys_id);
gaValues.getXMLAnswer( function(answer) {
var values = JSON.parse(answer);
// Populate first select box
values.select1.forEach( function(item) {
resolutionSelect1.insert(new Element('option', {
value: item.value.value
}).update(item.label.value));
});
// If first select box has initial value, populate second select box
if (values.initial.u_select_1) {
resolutionSelect1.value = values.initial.field1; // fill from the Incident
resolutionSelect1Wrapper.addClassName('is-filled'); // don't call the onChange
values.select2.forEach( function(item) {
resolutionSelect1.insert(new Element('option', {
value: item.value.value
}).update(item.label.value));
}
if (values.initial.u_select_2) {
resolutionSelect2.value = values.initial.u_select_2;
resolutionSelect2OnChange();
}
// Populate initial value for reference field
if (values.initial.u_reference) {
resolutionReference.value = values.initial.u_reference.value;
resolutionReferenceDisplay.value = values.initial.u_reference.display;
resolutionReferenceOnChange();
});
I didn't run the onChange function for the first select box, but manually set the "is-filled" class. This is because the onChange for the first select box makes a GlideAjax call and rebuilds the options for the second select box, but we don't want that to happen for the initial load. The onChange functions for the 4 fields would be something like this:
function resolutionSelect1OnChange() {
if(!resolutionSelect1.value)
resolutionSelect1Wrapper.removeClassName('is-filled');
else
resolutionSelect1Wrapper.addClassName('is-filled');
// empty the field, and mark it unfilled, then remove the old choices
resolutionSelect2.value = "";
resolutionSelect2Wrapper.removeClassName('is-filled');
for (var i = resolutionSelect2.options.length - 1; i >= 0; i--) {
resolutionSelect2.remove(resolutionSelect2.options[i]);
}
// repopulate the "-- None --" option
resolutionSelect2.insert(new Element('option', {
value: ""
}).update(resolutionSelect2.getAttribute("placeholder")));
var gaSelect2 = new GlideAjax('MyMIMAjaxUtil');
gaSelect2.addParam('sysparm_name', 'getSelect2');
gaSelect2.addParam('sysparm_dependent_value', resolutionSelect1.value);
gaSelect2.getXMLAnswer(function(answer) {
var options = JSON.parse(answer);
options.forEach(function(item) {
resolutionSelect2.insert(new Element('option', {
value: item.value.value
}).update(item.label.value));
});
});
enableResolveBtn();
}
function resolutionSelect2OnChange() {
if(!resolutionSelect2.value)
resolutionSelect2Wrapper.removeClassName('is-filled');
else
resolutionSelect2Wrapper.addClassName('is-filled');
enableResolveBtn();
}
function resolutionYesNoOnChange() {
if(!resolutionYesNo.value.trim()) {
resolutionYesNoWrapper.removeClassName('is-filled');
}
else {
resolutionYesNoWrapper.addClassName('is-filled');
}
if (resolutionYesNo.value.trim() == "Yes") {
resolutionReferenceMandatory.addClassName('required-marker');
resolutionReferenceMandatory.setAttribute('mandatory', true);
resolutionReferenceWrapper.removeClassName('hidden');
}
else {
resolutionReference.value = "";
resolutionReferenceMandatory.setAttribute('mandatory', false);
resolutionReferenceWrapper.addClassName('hidden');
resolutionReferenceWrapper.removeClassName('is-filled');
}
enableResolveBtn();
}
function resolutionReferenceOnChange() {
if(!resolutionReference.value.trim()) {
resolutionReferenceWrapper.removeClassName('is-filled');
// resolutionReferenceInfo.style.display = 'none'; // if the "i" button worked, this would hide it
}
else {
resolutionReferenceWrapper.addClassName('is-filled');
// resolutionReferenceInfo.style.display = ''; // if the "i" button worked, this would display it
}
enableResolveBtn();
}
One note: I populated the placeholder on the second select box in the Jelly code to hold the internationalized value of "-- None --". I did this because I couldn't figure out how to properly remove all options but the "-- None --" and I wanted to avoid making an Ajax call for the message every time I erase and update the options. You could use getMessage("None", callback) in the client script if you prefer not to use the placeholder this way.
I also had to modify the enableResolveBtn() to check if the Yes/No was set to Yes, and if so, check that the reference field had a value.
if(resolutionNotes.value.trim() && resolutionCode.value && resolutionSelect1.value && resolutionSelect2.value && resolutionYesNo.value
&& ((resolutionYesNo.value == "Yes" && resolutionReference.value) || (resolutionYesNo.value != "Yes" && !resolutionReference.value)))
Hopefully that's all clear enough.

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Yes that does! Thank you very much for the explanation.
-Sasha
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Sasha,
Can you share how you made the reference? I have added the field but it's unable to detect whether the field is populated. The Resolve button is not enabled even if I have filled-out the required variables.
<div class="form-group" id="kb-wrapper">
<label class="control-label col-sm-2" for="mim-kb">
<span mandatory="true" class="required-marker label_description"><span class="sr-only">${gs.getMessage('required')}</span></span> ${gs.getMessage('Knowledge Article')}
</label>
<div class="col-xs-12 col-md-8 form-field">
<g:ui_reference alt="Knowledge Article" name="number" id="number" table="kb_knowledge" order_by="short_description" onchange="resolveModal.kbOnChange()"/>
</div>
</div>
function kbOnChange() {
if(!kb.value.trim())
kbWrapper.removeClassName('is-filled');
else
kbWrapper.addClassName('is-filled');
enableResolveBtn();
}
I also have a requirement to check custom mandatory fields prior to resolving the incidents like Diagnosis and Resolution Time. Any idea how I can copy the values from the incident record to the Resolve Modal pop-up in Workbench?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello I made the changes, but drop down options are not reflecting, I put some logs and realized the script include it is not calling from UI page client script, checked the code thrice, every thing is correct, but not sure why options drop down are not populating to select. Can you please help

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
A common issue is the script include not being checked as "client callable" or not being in the Major Incident Management scope.
If you posted some screenshots of your client side code and script include, I could help more.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello Sasha, Please find the screenshot
The below code is added in UI page