Populate MRVS variables as a pop-up window in UI Action of Approval Table

sharvil Sheth1
Kilo Guru

I have one Multi Row Variable set, if user submits a request item then approval is triggered, when respective user opens the approval record to approve or reject, before preforming approval action there is one UI Action named eg: "iSeries Approval", when user clicks on "iSeries Approval" then a popup window appears where user should see the MRV's table, the same MRV's which is submitted in request item and in pop-up window beside each record of MRV's there should be a checkbox to check (True) which record should stay and we should not, if 2 records are selected out of 3 then same should be updated in requested item MRV's.

I have tried below codes but not working.

UI Page:
HTML:

<jelly xmlns:j="jelly:core" xmlns:g="glide">

<g:evaluate var="jvar_rows" object="true">
    var ritmId = RP.getWindowProperties().get('ritm_id');
    var rows = [];
   
    var ritm = new GlideRecord('sc_req_item');
    if (ritm.get(ritmId)) {
        // IMPORTANT: Verify this matches the 'Internal Name' of your Variable Set
        var mrvsName = 'department_role_description_golden_id_mstrplan';
        var mrvsString = ritm.variables[mrvsName];
       
        if (mrvsString) {
            rows = JSON.parse(mrvsString);
        }
    }
    rows;
</g:evaluate>

<div style="padding:15px;">
    <table border="1" cellpadding="6" width="100%" style="border-collapse:collapse; border: 1px solid #ddd; font-family: sans-serif; font-size: 12px;">
        <thead>
            <tr style="background-color: #f5f5f5; text-align: left;">
                <th style="width:30px; text-align:center;">Select </th>
                <th>Golden Profile</th>
                <th>Add or Replace</th>
                <th>Department</th>
                <th>Role</th>
                <th>Golden ID</th>
                <th>Primary</th>
            </tr>
        </thead>
        <tbody>
            <j:if test="${empty(jvar_rows)}">
                <tr><td colspan="7" style="text-align:center; padding:20px;">No data found for RITM: ${ritmId}</td></tr>
            </j:if>
           
            <j:forEach items="${jvar_rows}" var="jvar_row" indexVar="jvar_idx">
                <tr>
                    <td style="text-align:center;">
                        <input type="checkbox" name="row_index" value="${jvar_idx}" class="row-check" />
                    </td>
                    <td>${jvar_row.department_role_description_golden_id_variable}</td>
                    <td>${jvar_row.mstrpln_add_or_replace}</td>
                    <td>${jvar_row.department}</td>
                    <td>${jvar_row.role_description}</td>
                    <td>${jvar_row.golden_id}</td>
                    <td>${jvar_row.primary}</td>
                </tr>
            </j:forEach>
        </tbody>
    </table>

    <div style="margin-top: 15px; text-align: right;">
        <button type="button" class="btn btn-default" onclick="GlideModal.get().destroy()">Cancel</button>
        <button type="button" class="btn btn-primary" onclick="submitSelection()">Submit</button>
    </div>
</div>
</jelly>

Client Script:
var ritmId = '$[jvar_ritm_id]';
    var ga = new GlideAjax('MRVSApprovalUtil');
    ga.addParam('sysparm_name', 'getMRVSData');
    ga.addParam('sysparm_ritm_id', ritmId);
    ga.getXMLAnswer(function(answer) {
        var rows = JSON.parse(answer);
        var tbody = document.getElementById('mrvs_body');
       
        rows.forEach(function(row, index) {
            var tr = document.createElement('tr');
           
            // Individual Row Checkbox
            var tdCheck = document.createElement('td');
            tdCheck.style.textAlign = "center";
            tdCheck.style.border = "1px solid #ddd";
            tdCheck.innerHTML = '<input type="checkbox" class="row-check" value="' + index + '"/>';
            tr.appendChild(tdCheck);
           
            // Details Column
            var tdDetails = document.createElement('td');
            tdDetails.style.border = "1px solid #ddd";
            tdDetails.style.padding = "10px";
            var rowContent = "";
            for (var key in row) {
                rowContent += "<span><strong>" + key + ":</strong> " + row[key] + "</span> ";
            }
            tdDetails.innerHTML = rowContent;
            tr.appendChild(tdDetails);
           
            tbody.appendChild(tr);
        });
    });
//});

// Select All / Deselect All logic
function toggleAll(master) {
    var checkboxes = document.querySelectorAll('.row-check');
    for (var i = 0; i < checkboxes.length; i++) {
        checkboxes[i].checked = master.checked;
    }
}

function submitSelection() {
    var selectedRows = [];
    var checkboxes = document.querySelectorAll('.row-check:checked');
   
    checkboxes.forEach(function(cb) {
        selectedRows.push(cb.value);
    });

    if (selectedRows.length == 0) {
        alert("Please select at least one record to keep.");
        //alert(tbody);
        return;
    }

    var ritmId = '$[jvar_ritm_id]';
    var ga = new GlideAjax('MRVSApprovalUtil');
    ga.addParam('sysparm_name', 'updateRITM');
    ga.addParam('sysparm_ritm_id', ritmId);
    ga.addParam('sysparm_selected_rows', selectedRows.join(','));
    ga.getXMLAnswer(function(response) {
        alert(response);
        GlideModal.get().destroy();
        window.location.reload(); // Refresh to see updated RITM data
    });
}

Script Include:
Client callable: True
var MRVSApprovalUtil = Class.create();
MRVSApprovalUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {
 
    getMRVSData: function () {
var ritmId = this.getParameter('sysparm_ritm_id');
        var mrvsName = 'department_role_description_golden_id_mstrplan'; // REPLACE WITH YOUR INTERNAL NAME
        var ritm = new GlideRecord('sc_req_item');
        if (ritm.get(ritmId)) {
            return ritm.variables[mrvsName];
        }
    },

    updateRITM: function() {
        var ritmId = this.getParameter('sysparm_ritm_id');
        var selectedIndices = this.getParameter('sysparm_selected_rows').split(',');
        var mrvsName = 'department_role_description_golden_id_mstrplan'; // REPLACE WITH YOUR INTERNAL NAME

        var ritm = new GlideRecord('sc_req_item');
        if (ritm.get(ritmId)) {
            var allRows = JSON.parse(ritm.variables[mrvsName]);
            var filteredRows = [];
           
            selectedIndices.forEach(function(idx) {
                filteredRows.push(allRows[parseInt(idx)]);
            });

            ritm.variables[mrvsName] = JSON.stringify(filteredRows);
            ritm.update();
            return "The RITM has been updated with " + filteredRows.length + " rows.";
        }
    },
//      }
 type: 'MRVSApprovalUtil'
});

UI Action:
Client: True:
Form button: True
Active: true
onClick: openMyModal()

function openMyModal() {

 var ritmId = g_form.getValue('document_id');
    var gm = new GlideModal("mrvs_checkbox_page");
    gm.setTitle("Approval: Edit Requested Rows");
    gm.setPreference('ritm_id', ritmId);
  //  gm.setWidth(750);
    gm.render();
}

Attaching Screen short for eg:
3 REPLIES 3

Ankur Bawiskar
Tera Patron

@sharvil Sheth1 

this is heavy customization so I will recommend not do this requirement.

Regards,
Ankur
Certified Technical Architect  ||  10x ServiceNow MVP  ||  ServiceNow Community Leader

sharvil Sheth1
Kilo Guru

yes but customer is asking for it

@sharvil Sheth1 

why are you giving approvers the access to delete MRVS row?

not a good practice

How would system know in future that end user had submitted 3 rows?

how will the audit and reporting function

As ServiceNow consultants, we should recommend best‑practice solutions. Not every requirement needs to be implemented, as excessive customization leads to technical debt and upgrade risks.

💡 If my response helped, please mark it as correct and close the thread 🔒— this helps future readers find the solution faster! 🙏

Regards,
Ankur
Certified Technical Architect  ||  10x ServiceNow MVP  ||  ServiceNow Community Leader