Welcome to Community Week 2025! Join us to learn, connect, and be recognized as we celebrate the spirit of Community and the power of AI. Get the details  

How to establish snUtil feature in servicenow without installing plugin?

PrinceK78263780
Mega Contributor

Requirement:
In the Incident form, there is a field called Watchlist (field type: glide_list). This field allows adding multiple users, but to remove a user, we currently need to unlock the field first.

I need to develop a solution where, without unlocking the field, an X (cross) hyperlink appears beside each user, and clicking that X should remove the respective user.

Is it possible to achieve this?

1 ACCEPTED SOLUTION

Vishal_Jaiswal
Mega Guru

Hi @PrinceK78263780 ,

 

Create a on-change client script on the field watchlist and refer the below script.

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

    // --- Helper Functions ---
    // These are now nested correctly so they are always available.

    function snuRemoveFromList(event) {
        event.preventDefault();
        var spanElement = this.parentElement;
        var fieldName = spanElement.getAttribute("data-field");
        var valueToRemove = spanElement.getAttribute("data-value");

        var oldValues = g_form.getValue(fieldName).split(',');
        var newValues = oldValues.filter(function(item) {
            return item.trim() !== valueToRemove.trim();
        });

        g_form.setValue(fieldName, newValues.join(','));
        
        // Corrected: Only call the function with a delay.
        setTimeout(renderCustomGlideList, 100);
    }

    function renderCustomGlideList() {
        try {
            document.querySelectorAll('div[type=glide_list]').forEach(function(elm) {
                var field = elm.id.split('.')[2];
                if (field !== '<watchlist_Field_value_name>') {
                    return;
                }

                var table = g_form.getGlideUIElement(field).reference;
                if (!table || table === 'null') return;

                var displayP = elm.nextSibling.querySelector('p');
                if (!displayP) return;
                displayP.style.display = 'inline';

                var options = document.querySelectorAll(`select[id$=${field}] option`);
                var labels = [...options].map(option => option.innerText);
                var values = elm.nextSibling.querySelector('input[type=hidden]').value.split(',');

                if (labels.length != values.length) return;

                var links = [];
                for (var i = 0; i < labels.length; i++) {
                    if (values[i] != "") {
                        var removeButton = `<a title="Remove" class="remove icon icon-cross" href="#" style="font-size:8pt; color:red; padding-right:4px; vertical-align: middle;"></a>`;
                        var itemHtml = `<span style='white-space: nowrap' data-field="${field}" data-value="${values[i]}">` +
                            removeButton +
                            `<a href="/${table}.do?sys_id=${values[i]}" target="_blank">${labels[i]}</a>` +
                            `</span>`;
                        links.push(itemHtml);
                    }
                }

                var html = links.join(', ');
                displayP.innerHTML = html;

                displayP.querySelectorAll('.remove').forEach(function(removeElm) {
                    removeElm.addEventListener('click', snuRemoveFromList);
                });
            });
        } catch (e) {}
    }

    // --- Main Execution Logic ---
    
    // If the field is cleared, do nothing (but let the UI clear the links).
    if (newValue === '') {
       return;
    }
    
    // This single call will now handle both the onLoad event and every subsequent onChange event.
    renderCustomGlideList();
}

 

View solution in original post

2 REPLIES 2

Vishal_Jaiswal
Mega Guru

Hi @PrinceK78263780 ,

 

Create a on-change client script on the field watchlist and refer the below script.

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

    // --- Helper Functions ---
    // These are now nested correctly so they are always available.

    function snuRemoveFromList(event) {
        event.preventDefault();
        var spanElement = this.parentElement;
        var fieldName = spanElement.getAttribute("data-field");
        var valueToRemove = spanElement.getAttribute("data-value");

        var oldValues = g_form.getValue(fieldName).split(',');
        var newValues = oldValues.filter(function(item) {
            return item.trim() !== valueToRemove.trim();
        });

        g_form.setValue(fieldName, newValues.join(','));
        
        // Corrected: Only call the function with a delay.
        setTimeout(renderCustomGlideList, 100);
    }

    function renderCustomGlideList() {
        try {
            document.querySelectorAll('div[type=glide_list]').forEach(function(elm) {
                var field = elm.id.split('.')[2];
                if (field !== '<watchlist_Field_value_name>') {
                    return;
                }

                var table = g_form.getGlideUIElement(field).reference;
                if (!table || table === 'null') return;

                var displayP = elm.nextSibling.querySelector('p');
                if (!displayP) return;
                displayP.style.display = 'inline';

                var options = document.querySelectorAll(`select[id$=${field}] option`);
                var labels = [...options].map(option => option.innerText);
                var values = elm.nextSibling.querySelector('input[type=hidden]').value.split(',');

                if (labels.length != values.length) return;

                var links = [];
                for (var i = 0; i < labels.length; i++) {
                    if (values[i] != "") {
                        var removeButton = `<a title="Remove" class="remove icon icon-cross" href="#" style="font-size:8pt; color:red; padding-right:4px; vertical-align: middle;"></a>`;
                        var itemHtml = `<span style='white-space: nowrap' data-field="${field}" data-value="${values[i]}">` +
                            removeButton +
                            `<a href="/${table}.do?sys_id=${values[i]}" target="_blank">${labels[i]}</a>` +
                            `</span>`;
                        links.push(itemHtml);
                    }
                }

                var html = links.join(', ');
                displayP.innerHTML = html;

                displayP.querySelectorAll('.remove').forEach(function(removeElm) {
                    removeElm.addEventListener('click', snuRemoveFromList);
                });
            });
        } catch (e) {}
    }

    // --- Main Execution Logic ---
    
    // If the field is cleared, do nothing (but let the UI clear the links).
    if (newValue === '') {
       return;
    }
    
    // This single call will now handle both the onLoad event and every subsequent onChange event.
    renderCustomGlideList();
}