Creating a Custom Slushbucket Popup Dialog

Happy New Year! Hopefully everybody had a great holiday. Mine was spent mostly helping my kids to break in some new toys :). I did get some time to play with some new Service-now ideas as well. I’ll be sharing some very cool stuff here on SNCGuru over the next couple of weeks.
I’ve seen a couple requests recently for a way to allow users to select items from a slushbucket popup dialog. The most common reason for this is to help manage manual group approvals on a task record. If you’ve worked with group approvals at all, you’ve probably noticed that they work a little bit differently than regular approval records do. Group approval records are really just task records so you can’t just hit an ‘Edit’ button and add groups to be approvers on a task. Instead, you have to repeatedly click the ‘New’ button and create a new task record for each approval group. Normally this isn’t an issue because group approvals are typically managed in workflow but if you’re manually adding a lot of these, the process can be fairly tedious.
This article shows how you can provide a better UI by creating a slushbucket popup dialog that allows users to select one or many groups to add as approvers on a task. Even though the solution is designed for a specific use case, I’ve tried to make the example shown here generic enough so that you can easily modify it for other uses as well.

The first piece to this solution is to create a trigger for the dialog. For this solution, a UI action probably makes the most sense. The end user will click a UI action to display the popup dialog and make the necessary selections there.

‘Add Approval Groups’ UI Action
Name: Add Approval Groups
Client: true
Form link: true
OnClick: addApprovalGroups()
Condition: gs.hasRole(‘itil’)

function addApprovalGroups(){
   //Open a dialog window to select Approval Groups
   var dialog = new GlideDialogWindow('add_approval_groups');
   dialog.setTitle('Add Approval Groups');
   dialog.setPreference('sysparm_groupQuery', 'active=true');
   //Make sure to not submit the form when button gets clicked
   return false;

The UI action opens the dialog with a call to a specific UI page. The UI page is what contains most of the logic for the slushbucket. It includes the actual HTML (which pulls in the slushbucket and UI buttons from UI macros) as well as the client script that loads the groups and makes a call to insert group approval records.

‘add_approval_groups’ UI Page
Name: add_approval_groups

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
            Please select the groups you wish to add as approvers.
            <!-- Include the 'ui_slushbucket' UI macro -->
         <TD align="right">
            <!-- Include the 'dialog_buttons_ok_cancel' UI macro -->
            <g:dialog_buttons_ok_cancel ok="return continueOK()" cancel="return continueCancel()" ok_type="button" cancel_type="button"/>

Client script:

//Called when the 'OK' button gets clicked
function continueOK(){
   //Get the selected values from the right slushbucket
   var values = slush.getValues(slush.getRightSelect());
   //Get the sys_id of the current record
   var taskID = g_form.getUniqueValue();
   //Make sure we have at least one selection
   if(values == ''){
      alert("At least one group must be selected");

   //Add the group approval records
   var ajax = new GlideAjax('GroupSelectAjax');
   ajax.addParam('sysparm_name', 'groupsAdd');
   ajax.addParam('sysparm_taskID', taskID);
   ajax.addParam('sysparm_values', values);

//Called when we get a response from the 'continueOK' function
function addGroupResponse(){
   return false;

//Called when the 'Cancel' button gets clicked
function continueCancel(){
   //Close the dialog window
   return false;

//Called when the form loads
   //Load the groups when the form loads
   var ajax = new GlideAjax('GroupSelectAjax');
   ajax.addParam('sysparm_name', 'getGroups'); 
   return false; 

//Called when we get a response from the 'addLoadEvent' function
function loadResponse(response){
   //Process the return XML document and add groups to the left select
   var xml = response.responseXML;
   var e = xml.documentElement; 

   var items = xml.getElementsByTagName("item");
   if(items.length == 0)

   //Loop through item elements and add each item to left slushbucket
   for (var i = 0; i < items.length; i++) {
      var item = items[i];
      slush.addLeftChoice(item.getAttribute('value'), item.getAttribute('text'));

Many times, you can stop with the UI page. In this case, it makes sense for us to do some of our heavy-lifting for populating the groups in the slushbucket and creating group approval records at the server. The client scripts in the UI page make GlideAjax calls to the functions in a script include. The script include performs the query and returns an XML response back to the client so that it can continue.

‘GroupSelectAjax’ Script Include
Name: GroupSelectAjax
Client callable: true

var GroupSelectAjax = Class.create();

GroupSelectAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
   //Get and return a list of groups (name and sys_id)
   getGroups: function() {  
      var gr = new GlideRecord("sys_user_group");
      gr.addQuery('active', true);  

      //Add the available groups to select from
      while ( {
         var item = this.newItem();
         item.setAttribute('value', gr.getValue('sys_id'));
         item.setAttribute('text', gr.getValue('name'));

   //Take a taskID and group sys_id values and add 'sysapproval_group' records
   groupsAdd: function() {
      var taskID = this.getParameter('sysparm_taskID');
      var values = this.getParameter('sysparm_values').split(',');
      //Iterate through the group sys_id values
      for(x in values){
         var rec = new GlideRecord('sysapproval_group');
         rec.parent = taskID;
         rec.assignment_group = values[x];
         rec.approval = 'requested';

Date Posted:

January 4, 2011

Share This:


  1. Arlen February 25, 2011 at 3:30 am

    Hello Mark and hope all is well over there in sunny Cali :)

    Not sure if our requirements deem a new slushbucket pop up but I’m hoping you can provide some steer.

    On the approver related list in the incident module the ability exists to click on the ‘Edit’ global UI action and add manual approvers. This is pretty much OOB functionality. However, if the need arises to add the same approver again later in the process, the slushbucket does not allow it since the person already exists on the right hand side. Therein lies our challenge. To have the ability to add the same approver again.

    We have narrowed down the global ‘Edit’ UI action and even tampered with one to many and many to many options none of which yielded the desired outcome.

    Here’s the OOB script for one to many Edit slushbucket which I feel needs to have some code added/removed:

    var uri = action.getGlideURI();
    var path = uri.getFileFromPath();
    uri.set('sysparm_m2m_ref', current.getTableName());
    uri.set('sysparm_collection_related_file', current.getTableName());
    uri.set('sysparm_form_type', 'o2m');
    uri.set('sysparm_stack', 'no');

    Any help or ideas will be greatly appreciated.

    • Mark Stanger February 25, 2011 at 3:36 am

      I doubt if you’ll be able to do what you want by modifying the edit button functionality. I’ve never seen that done before. The popup dialog solution should work for you though. All you would have to do is modify it to use the ‘sys_user’ table and the ‘sysapproval_approver’ table.

  2. Abhiram Bharadwaj May 9, 2011 at 10:53 pm

    Hey mark,

    If i want to use a reference field, in place of slush button, I have to use the UI reference field is it?

    How do i access this in the Client Script?

    Thanks !

    • Mark Stanger May 10, 2011 at 12:32 am

      Yes, if you want to use a reference field in a custom popup dialog, you should include the ‘ui_reference’ macro instead of the ‘ui_slushbucket’ macro. The basic code to include in your UI page looks something like this…


      To access the value of that field when the ‘OK’ button is clicked, you can use a client script like this…
      [cc lang=”javascript”
      //Called when the ‘OK’ button gets clicked
      function continueOK(){
      //Get the value of the dialog reference field
      var dialogFieldValue = gel(‘YOUR_DIALOG_REFERENCE_FIELD_NAME’).value;
      //Set the value into a field on the form (optional)
      //g_form.setValue(‘YOUR_FORM_REFERENCE_FIELD’, dialogFieldValue);

      If you want to filter the entries in the reference field using a reference qualifier then you have to include an encoded query string using a special syntax in the ‘Name’ parameter. That syntax looks something like this…

      <g:ui_reference name="QUERY:active=true" table="REFERENCED_TABLE_NAME"> 

      Because the ‘Name’ parameter ends up being the ID of the form element too in this case, you need to reference the field by this custom query string to get the value in your client script if you’ve applied a filter. This is a terrible design, but that’s just how it was developed. :)

      //Get the value of the dialog reference field 
      var dialogFieldValue = gel('QUERY:active=true').value; 
      • Michael Brown December 6, 2011 at 2:42 pm

        Nice Reference Qualifier tip on the ui_reference fields. I needed that. The whole ID thing is dumb though.

  3. Abhiram Bharadwaj May 11, 2011 at 2:30 am

    Thanks a ton ! :)

  4. Abhiram Bharadwaj June 3, 2011 at 9:59 pm

    Hey Mark,

    I know this requirement is weird :-s,but then thought you have some fix for this

    There is a field on the service-request form, which value we have to use to filter the reference field which is populated through a Glide window. The filtering should happen before even the service request form is submitted. i.e once the field on the form is filled.

    Can that be done?


    • Mark Stanger June 4, 2011 at 2:35 am

      I think it can, but I don’t have a specific example of that at the moment. You’ll need to ask this one on the forums if you need more help.

  5. Abhiram Bharadwaj June 6, 2011 at 11:58 pm

    Thanks.. Sure, will do that ..

  6. Mike P. August 10, 2011 at 9:35 am

    Hi Mark,
    Do you think this is something that can be tailored to allow users to select multiple CI’s to a Change/Incident/Etc?

    Kind Regards,
    Mike P.

    • Mark Stanger August 10, 2011 at 9:37 am

      I suppose it could, but I don’t think it’s necessary in that case. The ‘Edit’ button on the ‘Affected CIs’ related list has always worked well for me.

      • Mike P. August 10, 2011 at 10:15 am

        I agree that the Edit button for the related list works well. Although my understanding of the ‘Affected CIs’ are the CIs that are impacted by the Change/Incident/Etc. As an example, I would like to have a list of CIs that will be used in a single Change Request and also have the list of impacted CIs in the “Affected CIs” related list.

        I hope that makes sense.

        Thanks for your time.

  7. Marc August 12, 2011 at 3:43 am

    Hi Mark,

    do you know if there is a way to auto-populate the right side of the slush with the left values, i.e. values start on the right as selected instead of left as available?

    The business case is I’ve built this for a change task and approval chase UI, but the customer wants to opt out of whom should receive the chase, instead of opt in.


    • marc guy August 12, 2011 at 3:56 am

      sorry, I figured it out but here’s what I done for anybody else, so this populates the right instead of the left so you can unselect items rather than select them.

      this goes in the UI Page client script, right at the very bottom, I’ve left the uncommented line there so you can see where it goes.

      //      slush.addLeftChoice(item.getAttribute('value'), item.getAttribute('text'));
      	   var opt = cel("option");
      	   opt.value = item.getAttribute('value');
      	   opt.text = item.getAttribute('text');
  8. mjd March 6, 2012 at 12:12 am

    Thanks for this example.
    Where can I find a detailed description about slush bucket functions like slush.addLeftChoice() , slush.clear() etc.

    • Mark Stanger March 6, 2012 at 4:19 am

      Might have to ask support on this one. You can find a lot of it with a dom inspector though.

  9. Kai Lempinen September 3, 2012 at 10:24 pm

    Hi Mark and thanks for a great post!

    Is there possibility to add “Add Filter”, “Run Filter” and the actual filters – similar to Configuration Item relationship UI page?

    Kind Regards,

    • Mark Stanger September 4, 2012 at 5:49 am

      Thanks. I’m sure it’s possible, but it’s not something I’ve built before. I imagine that type of thing would be fairly complex to implement.

  10. R. Hodgins January 8, 2013 at 1:40 pm

    I am working on a requirement that has put us in need of putting a List Collector into a change form — in several places. I am not much of a Jelly developer (a few simple UI Pages but that is about it) but I ‘know’ that it should be possible to write a control in place in a form.

    The requirement we have is to provide a filtered list of choices from which the user will multi-select. We need up to 6 in a few of the forms we are building and need to locate the Collectors in the form context.

    Can you suggest how this might be done? I suspect that this has come up before. I like the popup solution but having a string of UI Action buttons located away from the relevant form sections will not work for the client. Additionally, we need to have the selections persist and be editable by the end user in several approval passes.

    • Mark Stanger January 9, 2013 at 5:16 pm

      There’s really only a couple of ways that you could do this. The first (and probably best) solution would be to create those changes using a record producer that contained the list collector variables you need. These variables could even be hidden from the end user on the initial form. Using the record producer would allow you to display the variables on your change form in the variable editor so they could be used throughout the change flow.
      The other option would be to set these options up in related lists or list fields on the change form.

      • R. Hodgins January 11, 2013 at 7:22 pm

        Actually, we went a third way….

        1. Create a New UI Macro for the control
        a. Give it a meaningful name and description
        b. Add a no-frills wrapper to the SNC Slushbucket control…

        2. Create a Formatter to make control available in your Form.
        UI Formatter:
        a. Name: something useful
        b. Formatter: .xml
        c. Table: The table of the Form you are building
        d. Type: Formatter
        e. Active: True

        3. Insert the control (formatter) in your form page.
        a. Personalize -> Form Layout
        b. Add the new Formatter to your layout where you want it

        4. Add a new string variable to hold selected sys_ids ( judge the size accordingly).
        a. Name the variable to something easily recognizeable.
        b. Create a UI Policy and hide it from the end user [view it only to debug]

        Client Script the control behaviors

        onLoad – Fill the control with previous data, if any.

        function onLoad() {
        setTimeout(addAccessDeptChoices, 1000)

        function addAccessDeptChoices() {
        //accessdept.clear() Clears out the two sides of the slushbucket

        // our query filter requirements reside in u_dsa_department
        var departments = new GlideRecord(‘cmn_department’);
        departments.addQuery(‘parent’, g_form.getValue(‘u_dsa_department’) );

        while( {


        var selectedValues = (g_form.getValue(‘u_accessdept_value’)+”).split(‘,’);

        OnChange() for the query Filter requirement.

        function onChange(control, oldValue, newValue, isLoading, isTemplate) {
        if (isLoading) {


        function filterAccessDeptChoices(value) {
        accessdept.clear(); //Clears out the two sides of the slushbucket

        if (value==”){

        // our query filter requirements reside in u_dsa_department
        var departments = new GlideRecord(‘cmn_department’);
        departments.addQuery(‘parent’, g_form.getValue(‘u_dsa_department’) );

        while( {

        var selectedValues = (g_form.getValue(‘u_accessdept_value’)+”).split(‘,’);

        OnSubmit – Save the user selections.

        function onSubmit() {

        var slushBucketNames = [‘accessdept’];

        var values = [];
        jQuery(‘#’ + name + ‘_right option’).each(function() {

        g_form.setValue(‘u_’ + name + ‘_value’, values.join(‘,’));



        It works, too. There are two pieces I have not worked out yet; a search like the List Collector has and how to make the control wider for the rather long-named choices the user must select among.

        Any thoughts? (and help on either of the two items on my to-do list would be most welcome.

        • R. Hodgins January 11, 2013 at 8:02 pm

          The previous post ate the scripts for the first piece:


          Hopefully it comes thru… it is just a glide declaration of a ui_slushbucket named ‘accessdept’

  11. Lou January 24, 2013 at 3:37 pm

    can this work on adding CI to the Affected CI related list instead of approvers, that is referencing a specific cmdb table, i.e. CMDB_CI_GROUPS.

    if what would be the changes, if anyone can help, greatly appreciate.

    • Lou January 24, 2013 at 4:42 pm

      I am thinking the only change to make using this is to change the script include – GrouAdd function. here’s what I have tried but it is not working,,

      //Take a taskID and group sys_id values and add ‘cmdb_ci_group’ records
      groupsAdd: function() {
      var taskID = this.getParameter(‘sysparm_taskID’);
      var values = this.getParameter(‘sysparm_values’).split(‘,’);
      //Iterate through the group sys_id values
      for(i in values){
      var rec = new GlideRecord(‘task_ci’);
      rec.task = taskID;
      rec.ci_item = values[i];

  12. Jason Thomas July 8, 2013 at 1:52 am

    Hi Mark

    I’d like to suggest a modification to the addGroupResponse function, as I found that users will and do click this button before completing the form
    and are greeted with a message that mandatory field x isn’t completed.

    From this

    function addGroupResponse(){

    To this

    function addGroupResponse(){
       return false;

    Instead of saving the form, it simply refreshes the related list, therefore the user doesn’t need to complete the form before clicking the add approval groups

    • Mark Stanger July 8, 2013 at 6:28 am

      Great suggestion. This is a great use of the ListV2 refresh capabilities. Thanks!

  13. June December 19, 2013 at 6:53 pm

    Hi Mark,
    This dialog box is great but I have one question. How do I show the approval groups that are already on the Change Request on the right hand side of the slushbucket, the way the approvers are listed. Any help would be appreciated. Thanks !!!

    • Mark Stanger December 19, 2013 at 8:33 pm

      It’s possible, but not easily explained. I don’t have a pre-built example for it either unfortunately. The ‘addLoadEvent’ function will need to be modified to call a new function in the script include to get the current groups from the group approval records. The ‘loadResponse’ section in the client script is what takes that information and populates it in the left side. You’ll need to extend that to receive items for the other side and parse and populate them similarly.

  14. Travis DePuy January 27, 2015 at 11:21 am

    I added a search/filter input with an onchange to help manage a large list. However, i found that both sides of the slushbucket were getting cleared. I did some digging and added a note here:

  15. Richard May 29, 2015 at 8:38 pm

    Is it possible to use 2 slush buckets on a a single ui page, if so how do you populate/clear them both?

    • Richard May 29, 2015 at 8:45 pm

      I figured it out. You add a name and in the client script you use the name instead of “slush”.

  16. Divya March 3, 2017 at 5:31 am

    Hi Mark Thanks for the script . I used the same UI page and script include for my requirement .

    My requirement is If I select some groups in the slush bucket and then click OK. Approval groups should appear Approved in the related list .

    But until i refresh the page the approval record in the related list is not getting updated,.

    Can u pls help me with this ?

    I used exactly same code of urs with some changes

  17. Manisha Maurya July 14, 2017 at 6:53 am

    Hi Mark,

    Im trying to export the tabel data from a custom UI page in excel sheet, it works for chrome but not for IE. If you could look in to the issue then plz let me know. I will share the codes here.

Comments are closed.




Fresh Content
Direct to Your Inbox

Just add your email and hit subscribe to stay informed.