onchange client scripts not working in service operation workspace but it is working in classic Ui

abhishek153
Tera Contributor

I had created two on change client scripts on incident table.
the requirement is:
case1: when initially creating incident if the business service is field services the assignment group should not auto populate
case2: when the business service is other than business service the assignment group should automatically populate based on service offering
cae3: when the other business service already existing incident we are changing into business service the assignment group should update the previous assignment group.

I had achieved this through on change client scripts on business service and service offering 

on change client script for business service:

function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || !newValue) return;

    var FIELD_SERVICE_SYSID = '516aad7347e02650e9753cc7536d4313';
    var prevGroup = g_form.getValue('assignment_group');

    // Always remember what was there before changing
    if (prevGroup)
        g_scratchpad._lastAG = prevGroup;

    // Wait until the reference-qualifier refresh on Service Offering is finished
    setTimeout(function() {
        var bsSysId = g_form.getValue('business_service');
        if (!bsSysId) return;

        // === Switched to Field Service ===
        if (bsSysId === FIELD_SERVICE_SYSID) {
            if (g_scratchpad._lastAG) {
                console.log('Restoring previous AG:', g_scratchpad._lastAG);
                g_form.setValue('assignment_group', g_scratchpad._lastAG);
            } else {
                console.log('No previous AG → clear');
                g_form.clearValue('assignment_group');
            }
            return;
        }

        // === Any other BS → normal autopopulate ===
        var soVal = g_form.getValue('service_offering');
        if (!soVal) {
            g_form.clearValue('assignment_group');
            return;
        }

        var ga = new GlideAjax('AutoPopulateUtils');
        ga.addParam('sysparm_name', 'getSupportGroupForOffering');
        ga.addParam('sysparm_offering', soVal);
        ga.getXMLAnswer(function(resp) {
            if (resp) {
                g_form.setValue('assignment_group', resp);
                g_scratchpad._lastAG = resp;
            } else {
                g_form.clearValue('assignment_group');
            }
        });
    }, 800); // delay long enough for SO refqual refresh
}
 
onchange client script for service offering:

function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || !newValue) return;
 
    var FIELD_SERVICE_SYSID = '516aad7347e02650e9753cc7536d4313';
    if (g_form.getValue('business_service') === FIELD_SERVICE_SYSID) {
        console.log('SO changed but BS = Field Service → skip');
        return;
    }
 
    var ga = new GlideAjax('adidas_populate_assignment_group');
    ga.addParam('sysparm_name', 'populateGroups');
    ga.addParam('sysparm_service', newValue);
    ga.getXMLAnswer(function(ans) {
        if (ans) {
            g_form.setValue('assignment_group', ans);
            g_scratchpad._lastAG = ans;
        } else {
            g_form.clearValue('assignment_group');
        }
    });
}

these scripts are executing as expected in classic Ui. but I want this to execute in service operation workspace (sow) also.

I had kept Ui type =All and also tried by removing global checkbox and setting view as sow but it is not worked.
Also tried business rule, script include also it was not worked.

Please help me with the solution that should work in service operation workspace. 

Thanks in Advance!

Thanks & Regards,
Abhishek.






2 ACCEPTED SOLUTIONS

Ankur Bawiskar
Tera Patron
Tera Patron

@abhishek153 

so what debugging did you do?

did you try adding alert in few places in your client script?

did you check GlideAjax got value when script ran in workspace?

💡 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  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

View solution in original post

MaxMixali
Giga Guru

Making Client Scripts Work in Service Operations Workspace (SOW)

What changes for Workspace
1. Use “Form Client Scripts” with UI Type = All (or Workspace)
- Open each client script → set UI type to All (or Workspace on newer releases).
- Scope them to the Incident table and the specific fields (business_service, service_offering).

2. Don’t rely on g_scratchpad or DOM timing hacks
- In Workspace, g_scratchpad is not guaranteed on the client.
- Avoid setTimeout (refqual timing differs in Workspace).
- Use a hidden field to track the “previous assignment group” (e.g., u_prev_assignment_group), and keep all logic event-driven.

3. GlideAjax works in Workspace
- Make sure your Script Include is Client callable and returns a sys_id for the group.
- Keep it in the same scope (or allow cross-scope) as the incident form.

Minimal, workspace-safe design
Hidden field:
Add a string/reference field on Incident: u_prev_assignment_group (not mandatory to show on the form).

1) onLoad Client Script (Form → onLoad)
Purpose: remember the starting AG when editing an existing record (supports your “case3”).

function onLoad() {
var ag = g_form.getValue('assignment_group');
if (ag)
g_form.setValue('u_prev_assignment_group', ag);
}

2) onChange – Business Service

If BS == Field Services → restore previous AG (or clear if none).
Else, if there’s a Service Offering → populate via GlideAjax. No setTimeout, no g_scratchpad.

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

var FIELD_SERVICE_SYSID = '516aad7347e02650e9753cc7536d4313';

if (newValue === FIELD_SERVICE_SYSID) {
var prev = g_form.getValue('u_prev_assignment_group');
if (prev) {
g_form.setValue('assignment_group', prev);
} else {
g_form.clearValue('assignment_group');
}
return;
}

var so = g_form.getValue('service_offering');
if (!so) {
g_form.clearValue('assignment_group');
return;
}

var ga = new GlideAjax('AutoPopulateUtils');
ga.addParam('sysparm_name', 'getSupportGroupForOffering');
ga.addParam('sysparm_offering', so);
ga.getXMLAnswer(function(resp) {
if (resp) {
g_form.setValue('assignment_group', resp);
g_form.setValue('u_prev_assignment_group', resp);
} else {
g_form.clearValue('assignment_group');
}
});
}

3) onChange – Service Offering

Skip if BS == Field Services. Otherwise auto-populate via GlideAjax (no timers).

function onChange(control, oldValue, newValue, isLoading) {
if (isLoading) return;

var FIELD_SERVICE_SYSID = '516aad7347e02650e9753cc7536d4313';
if (g_form.getValue('business_service') === FIELD_SERVICE_SYSID) {
return;
}

if (!newValue) {
g_form.clearValue('assignment_group');
return;
}

var ga = new GlideAjax('AutoPopulateUtils');
ga.addParam('sysparm_name', 'getSupportGroupForOffering');
ga.addParam('sysparm_offering', newValue);
ga.getXMLAnswer(function(ans) {
if (ans) {
g_form.setValue('assignment_group', ans);
g_form.setValue('u_prev_assignment_group', ans);
} else {
g_form.clearValue('assignment_group');
}
});
}

This satisfies:
Case1 (BS = Field Services → do not autopopulate; restore or clear),
Case2 (other BS → autopopulate from Service Offering),
Case3 (switching an existing Incident to Field Services → restore previous group).

Script Include (server) – client callable

var AutoPopulateUtils = Class.create();
AutoPopulateUtils.prototype = {
initialize: function() {},

getSupportGroupForOffering: function() {
var offeringId = this.getParameter('sysparm_offering');
var grp = '';
if (offeringId) {
var so = new GlideRecord('service_offering');
if (so.get(offeringId)) {
grp = so.u_default_assignment_group + '';
}
}
return grp;
},

type: 'AutoPopulateUtils'
};

Make sure:
- Client callable = true
- Returns a sys_id of the group

Workspace check-list
- Client Scripts type: Form – onChange / onLoad
- UI type: All (or Workspace)
- Hidden field u_prev_assignment_group present on the form
- Script Include: client callable, same scope
- No DOM / setTimeout; everything event-driven

Extra hardening (optional)
- Add a UI Policy to make assignment_group read-only when BS = Field Services.
- Add a Business Rule (server) as a safeguard to enforce same logic on API/inline edits.

Summary
With these changes:
- Your scripts now run in Service Operations Workspace as well as Classic UI.
- You eliminate timing and scratchpad issues.
- Logic remains consistent across UI frameworks.

View solution in original post

2 REPLIES 2

Ankur Bawiskar
Tera Patron
Tera Patron

@abhishek153 

so what debugging did you do?

did you try adding alert in few places in your client script?

did you check GlideAjax got value when script ran in workspace?

💡 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  ||  9x ServiceNow MVP  ||  ServiceNow Community Leader

MaxMixali
Giga Guru

Making Client Scripts Work in Service Operations Workspace (SOW)

What changes for Workspace
1. Use “Form Client Scripts” with UI Type = All (or Workspace)
- Open each client script → set UI type to All (or Workspace on newer releases).
- Scope them to the Incident table and the specific fields (business_service, service_offering).

2. Don’t rely on g_scratchpad or DOM timing hacks
- In Workspace, g_scratchpad is not guaranteed on the client.
- Avoid setTimeout (refqual timing differs in Workspace).
- Use a hidden field to track the “previous assignment group” (e.g., u_prev_assignment_group), and keep all logic event-driven.

3. GlideAjax works in Workspace
- Make sure your Script Include is Client callable and returns a sys_id for the group.
- Keep it in the same scope (or allow cross-scope) as the incident form.

Minimal, workspace-safe design
Hidden field:
Add a string/reference field on Incident: u_prev_assignment_group (not mandatory to show on the form).

1) onLoad Client Script (Form → onLoad)
Purpose: remember the starting AG when editing an existing record (supports your “case3”).

function onLoad() {
var ag = g_form.getValue('assignment_group');
if (ag)
g_form.setValue('u_prev_assignment_group', ag);
}

2) onChange – Business Service

If BS == Field Services → restore previous AG (or clear if none).
Else, if there’s a Service Offering → populate via GlideAjax. No setTimeout, no g_scratchpad.

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

var FIELD_SERVICE_SYSID = '516aad7347e02650e9753cc7536d4313';

if (newValue === FIELD_SERVICE_SYSID) {
var prev = g_form.getValue('u_prev_assignment_group');
if (prev) {
g_form.setValue('assignment_group', prev);
} else {
g_form.clearValue('assignment_group');
}
return;
}

var so = g_form.getValue('service_offering');
if (!so) {
g_form.clearValue('assignment_group');
return;
}

var ga = new GlideAjax('AutoPopulateUtils');
ga.addParam('sysparm_name', 'getSupportGroupForOffering');
ga.addParam('sysparm_offering', so);
ga.getXMLAnswer(function(resp) {
if (resp) {
g_form.setValue('assignment_group', resp);
g_form.setValue('u_prev_assignment_group', resp);
} else {
g_form.clearValue('assignment_group');
}
});
}

3) onChange – Service Offering

Skip if BS == Field Services. Otherwise auto-populate via GlideAjax (no timers).

function onChange(control, oldValue, newValue, isLoading) {
if (isLoading) return;

var FIELD_SERVICE_SYSID = '516aad7347e02650e9753cc7536d4313';
if (g_form.getValue('business_service') === FIELD_SERVICE_SYSID) {
return;
}

if (!newValue) {
g_form.clearValue('assignment_group');
return;
}

var ga = new GlideAjax('AutoPopulateUtils');
ga.addParam('sysparm_name', 'getSupportGroupForOffering');
ga.addParam('sysparm_offering', newValue);
ga.getXMLAnswer(function(ans) {
if (ans) {
g_form.setValue('assignment_group', ans);
g_form.setValue('u_prev_assignment_group', ans);
} else {
g_form.clearValue('assignment_group');
}
});
}

This satisfies:
Case1 (BS = Field Services → do not autopopulate; restore or clear),
Case2 (other BS → autopopulate from Service Offering),
Case3 (switching an existing Incident to Field Services → restore previous group).

Script Include (server) – client callable

var AutoPopulateUtils = Class.create();
AutoPopulateUtils.prototype = {
initialize: function() {},

getSupportGroupForOffering: function() {
var offeringId = this.getParameter('sysparm_offering');
var grp = '';
if (offeringId) {
var so = new GlideRecord('service_offering');
if (so.get(offeringId)) {
grp = so.u_default_assignment_group + '';
}
}
return grp;
},

type: 'AutoPopulateUtils'
};

Make sure:
- Client callable = true
- Returns a sys_id of the group

Workspace check-list
- Client Scripts type: Form – onChange / onLoad
- UI type: All (or Workspace)
- Hidden field u_prev_assignment_group present on the form
- Script Include: client callable, same scope
- No DOM / setTimeout; everything event-driven

Extra hardening (optional)
- Add a UI Policy to make assignment_group read-only when BS = Field Services.
- Add a Business Rule (server) as a safeguard to enforce same logic on API/inline edits.

Summary
With these changes:
- Your scripts now run in Service Operations Workspace as well as Classic UI.
- You eliminate timing and scratchpad issues.
- Logic remains consistent across UI frameworks.