Regarding Multi Row Variable Set

SayoojN
Tera Contributor

Hi,

Can Anyone explain how we can add a serial number for each rows? 
The serial number should be dynamically change when a row is inserted or deleted on the MRVS. 
Like in the attachment, the Row number should be auto populated with respect to the rows

This should be before the form submission. the all variables in the MRVS are mandatory, think so we can get this with a onChange client script

Please guide me.

2 ACCEPTED SOLUTIONS

Bhimashankar H
Mega Sage

Hi @SayoojN ,

 

For this you can implement something like this.

1. Add Read-only  Single-Line Text variable for serial number on MVRS.

 

2. Use a Catalog Client Script (onLoad or onChange) or Global Client Script to Update Serial Numbers

  • Applies to: A Catalog Item or A Record Producer (select the one where your MRVS resides).

function onLoad() {
    // Get the MRVS variable set name (replace 'your_mrvs_internal_name' with the actual internal name of your MRVS)
    // You can find the internal name by opening your MRVS record and looking at the 'Name' field.
    var mrvsName = 'your_mrvs_internal_name'; 
    var serialNumberVariableName = 'serial_number'; // The internal name of your serial number variable

    // Get the MRVS container element
    var mrvsContainer = g_form.getControl(mrvsName);

    if (!mrvsContainer) {
        console.warn('MRVS container not found: ' + mrvsName);
        return;
    }

    // --- Helper function to update row numbers ---
    function updateRowNumbers() {
        var rows = g_form.getControl(mrvsName + '.row_0').closest('.sc-multi-row-variableset-group').querySelectorAll('.sc-multi-row-row');
        if (rows.length === 0) {
            console.log("No rows found in MRVS.");
            return;
        }

        rows.forEach(function(rowElement, index) {
            var rowNumber = index + 1;
            // Find the specific serial number input within this row
            var serialInput = rowElement.querySelector('[name*="' + serialNumberVariableName + '"]');
            if (serialInput) {
                serialInput.value = rowNumber;
                // Trigger change event to ensure g_form recognizes the update
                // This is crucial for mandatory fields and saving the data
                g_form.setValue(serialInput.name, rowNumber); 
            }
        });
    }

    // --- Initial numbering on load ---
    updateRowNumbers();

    // --- Event listener for adding/removing rows ---
    // The challenge is that ServiceNow doesn't expose a direct API for MRVS row changes.
    // We need to listen for DOM mutations or rely on a polling mechanism.
    // A more robust way is to listen for clicks on "Add" and "Delete" buttons.

    // Find the MRVS add button
    var addButton = mrvsContainer.querySelector('.fa-plus-circle');
    if (addButton) {
        addButton.onclick = function() {
            // Use setTimeout to allow the new row to be fully rendered in the DOM
            setTimeout(updateRowNumbers, 50); 
        };
    } else {
        console.warn('MRVS Add button not found for ' + mrvsName);
    }

    // Find the MRVS container to listen for deletion.
    // Deletion buttons are created dynamically inside each row.
    // We'll use event delegation on the MRVS container.
    var mrvsRowsContainer = g_form.getControl(mrvsName + '.row_0').closest('.sc-multi-row-variableset-group');
    if (mrvsRowsContainer) {
        mrvsRowsContainer.addEventListener('click', function(event) {
            if (event.target.classList.contains('fa-times-circle') || event.target.closest('.fa-times-circle')) {
                // A delete button was clicked
                setTimeout(updateRowNumbers, 50); // Allow time for row removal
            }
        });
    } else {
        console.warn('MRVS rows container not found for ' + mrvsName);
    }


}

 

Please add your customization in this code regarding the name of variable and some other placeholders.

 

Some DOM Manipulation:

 

  • The script uses g_form.getControl(mrvsName + '.row_0').closest('.sc-multi-row-variableset-group'). This is a common pattern to get the main container of the MRVS rows. g_form.getControl(mrvsName + '.row_0') gets a control from the first row, and closest() then finds its parent MRVS group.

  • querySelectorAll('.sc-multi-row-row') selects all the individual row containers within the MRVS.

  • querySelector('[name*="' + serialNumberVariableName + '"]') is used to find the specific input field for your serial number variable within each row. The *= is a "contains" selector, useful because ServiceNow appends unique IDs to variable names in MRVS rows (e.g., _io_0_serial_number, _io_1_serial_number).

Serial Number for Each Row: The updateRowNumbers function iterates through each detected row and assigns index + 1 to the serial_number field.

Before Form Submission: All these actions happen client-side in the browser before the user clicks "Submit".

 

Give it try

 

 

Thanks,
Bhimashankar H

 

-------------------------------------------------------------------------------------------------
If my response points you in the right directions, please consider marking it as 'Helpful' & 'Correct'. Thanks!

View solution in original post

Ankur Bawiskar
Tera Patron
Tera Patron

@SayoojN 

you can use onLoad catalog client script which applies on MRVS and then access the MRVS value, check the row number in the previous row and then increment by 1

function onLoad(){

    // Get all rows in the MRVS
    var mrvs = g_service_catalog.parent.getValue('mvsVariableSetNameHere');

	// get this JSON and parse and get the previous row and then increment and set the row variable

    
}

AnkurBawiskar_0-1753426883980.png

 

If my response helped please mark it correct and close the thread so that it benefits future readers.

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

View solution in original post

2 REPLIES 2

Bhimashankar H
Mega Sage

Hi @SayoojN ,

 

For this you can implement something like this.

1. Add Read-only  Single-Line Text variable for serial number on MVRS.

 

2. Use a Catalog Client Script (onLoad or onChange) or Global Client Script to Update Serial Numbers

  • Applies to: A Catalog Item or A Record Producer (select the one where your MRVS resides).

function onLoad() {
    // Get the MRVS variable set name (replace 'your_mrvs_internal_name' with the actual internal name of your MRVS)
    // You can find the internal name by opening your MRVS record and looking at the 'Name' field.
    var mrvsName = 'your_mrvs_internal_name'; 
    var serialNumberVariableName = 'serial_number'; // The internal name of your serial number variable

    // Get the MRVS container element
    var mrvsContainer = g_form.getControl(mrvsName);

    if (!mrvsContainer) {
        console.warn('MRVS container not found: ' + mrvsName);
        return;
    }

    // --- Helper function to update row numbers ---
    function updateRowNumbers() {
        var rows = g_form.getControl(mrvsName + '.row_0').closest('.sc-multi-row-variableset-group').querySelectorAll('.sc-multi-row-row');
        if (rows.length === 0) {
            console.log("No rows found in MRVS.");
            return;
        }

        rows.forEach(function(rowElement, index) {
            var rowNumber = index + 1;
            // Find the specific serial number input within this row
            var serialInput = rowElement.querySelector('[name*="' + serialNumberVariableName + '"]');
            if (serialInput) {
                serialInput.value = rowNumber;
                // Trigger change event to ensure g_form recognizes the update
                // This is crucial for mandatory fields and saving the data
                g_form.setValue(serialInput.name, rowNumber); 
            }
        });
    }

    // --- Initial numbering on load ---
    updateRowNumbers();

    // --- Event listener for adding/removing rows ---
    // The challenge is that ServiceNow doesn't expose a direct API for MRVS row changes.
    // We need to listen for DOM mutations or rely on a polling mechanism.
    // A more robust way is to listen for clicks on "Add" and "Delete" buttons.

    // Find the MRVS add button
    var addButton = mrvsContainer.querySelector('.fa-plus-circle');
    if (addButton) {
        addButton.onclick = function() {
            // Use setTimeout to allow the new row to be fully rendered in the DOM
            setTimeout(updateRowNumbers, 50); 
        };
    } else {
        console.warn('MRVS Add button not found for ' + mrvsName);
    }

    // Find the MRVS container to listen for deletion.
    // Deletion buttons are created dynamically inside each row.
    // We'll use event delegation on the MRVS container.
    var mrvsRowsContainer = g_form.getControl(mrvsName + '.row_0').closest('.sc-multi-row-variableset-group');
    if (mrvsRowsContainer) {
        mrvsRowsContainer.addEventListener('click', function(event) {
            if (event.target.classList.contains('fa-times-circle') || event.target.closest('.fa-times-circle')) {
                // A delete button was clicked
                setTimeout(updateRowNumbers, 50); // Allow time for row removal
            }
        });
    } else {
        console.warn('MRVS rows container not found for ' + mrvsName);
    }


}

 

Please add your customization in this code regarding the name of variable and some other placeholders.

 

Some DOM Manipulation:

 

  • The script uses g_form.getControl(mrvsName + '.row_0').closest('.sc-multi-row-variableset-group'). This is a common pattern to get the main container of the MRVS rows. g_form.getControl(mrvsName + '.row_0') gets a control from the first row, and closest() then finds its parent MRVS group.

  • querySelectorAll('.sc-multi-row-row') selects all the individual row containers within the MRVS.

  • querySelector('[name*="' + serialNumberVariableName + '"]') is used to find the specific input field for your serial number variable within each row. The *= is a "contains" selector, useful because ServiceNow appends unique IDs to variable names in MRVS rows (e.g., _io_0_serial_number, _io_1_serial_number).

Serial Number for Each Row: The updateRowNumbers function iterates through each detected row and assigns index + 1 to the serial_number field.

Before Form Submission: All these actions happen client-side in the browser before the user clicks "Submit".

 

Give it try

 

 

Thanks,
Bhimashankar H

 

-------------------------------------------------------------------------------------------------
If my response points you in the right directions, please consider marking it as 'Helpful' & 'Correct'. Thanks!

Ankur Bawiskar
Tera Patron
Tera Patron

@SayoojN 

you can use onLoad catalog client script which applies on MRVS and then access the MRVS value, check the row number in the previous row and then increment by 1

function onLoad(){

    // Get all rows in the MRVS
    var mrvs = g_service_catalog.parent.getValue('mvsVariableSetNameHere');

	// get this JSON and parse and get the previous row and then increment and set the row variable

    
}

AnkurBawiskar_0-1753426883980.png

 

If my response helped please mark it correct and close the thread so that it benefits future readers.

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