Auto fill Service when entering Service Offering in Change form.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
Newby here. I'm labbing up the Change form in a Zurich based PDI.
I'm working on Services and Service Offerings. I have services created in table 'cmdb_ci_service_technical'. I have service offerings in table 'service_offering'. The Services are set as the parent on the offerings. I'm using CSDM5.
I want to configure my Change form to auto fill the Service when the Offering field is entered. Services will become read only when I figure this out.
I have this script assigned to the Service offering field as an onChange.
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading) {
return;
}
if (!newValue) {
g_form.clearValue('business_service');
return;
}
g_form.getReference('service_offering', function(offering) {
if (offering && offering.service) {
var serviceId = offering.service.toString();
g_form.setValue('business_service', serviceId);
} else {
g_form.clearValue('business_service');
}
});
}
If I enter the offering, I get an Invalid reference error. Any ideas? Maybe a howto doc on how to make this work?
Thanks All,
--Patrick
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago - last edited 3 weeks ago
Hi @Patrick Brown,
The Business Service and the Technical Service Offering do not have a direct relationship to query.
How are you going to find a unique value for the Business Service field with a given TSO? There are multiple n:m relationships between this two entities.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
You can't do that purely client side... You need a onChange client script with GlideAjax to a script include to obtain the technical service.
If my answer has helped with your question, please mark my answer as the accepted solution and give a thumbs up.
Best regards
Anders
Rising star 2024
MVP 2025
linkedIn: https://www.linkedin.com/in/andersskovbjerg/
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago - last edited 3 weeks ago
We implemented this awhile back, here's what we have working:
On-Change Field: service_offering
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
// This changes the Service (parent) when the offering is selected; assuming Service is empty
if(g_form.getValue('business_service') == ''){
g_form.setValue('business_service', g_form.getReference('service_offering').getValue('parent'));
}
}
We also implemented a UI Policy to make the Service Read-Only when the Offering is not empty. The ensured that we didn't get data mismatching.
To go a step further, we also configured the Service Offering Dictionary record; when Service is selected, Service Offerings are filtered to only the records associated to the Service that is selected. (see attachment)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2 weeks ago
@Nicholas Eblen @Patrick Brown
Do not use getReference. It fetches the entire GlideRecord when you only require the Sys ID, which is very inefficient and results in the user waiting client side for the value to load (at scale this can really slow a form down).
GlideAjax is the way to go. Remember to include the display value for the table as well or the client will make another trip to the server to retrieve it. There is also no reason to check whether the Service is empty when setting the Service offering - you are looking up a (potentially new) Service so just set it.
In addition many people believe it gives the maximum choice to make both Service and Service Offering fields selectable, but I think that is a mistake. Make the Service field read-only and set it from the Offering, every time. Educate users that Offering is the entry point. In any case the vast majority of Incidents, Changes and Problems are set by automation so bypass the UI, so as it's easy to enforce this for automation, do so for all. This leading practices guide on Incident gives more info: https://www.servicenow.com/community/itsm-articles/how-to-configure-incident-management-to-align-wit...
Disclaimer - test any code first before moving to a production instance. I am just as capable of typos as anyone else...
Client Script:
function onChange(control, oldValue, newValue, isLoading) {
if (isLoading || newValue == '') {
return;
}
var gaService = new GlideAjax('CsdmRelationshipAjax');
gaService.addParam('sysparm_name', 'getServiceFromOffering');
gaService.addParam('sysparm_offering', g_form.getValue('service_offering'));
gaService.getXMLAnswer(setService);
}
function setService(response) {
var serviceObj = JSON.parse(response);
if (serviceObj.serviceSysId && serviceObj.displayValue) {
g_form.setValue('business_service', serviceObj.serviceSysId, serviceObj.displayValue);
} else {
// Parent is a mandatory field on the Service Offering form so this should never be called
//...but you never know.
g_form.addErrorMessage(gs.getMessage('Cannot set Service or Service Offering if Service Offering does not have a parent Service.');
g_form.clearValue('business_service');
g_form.clearValue('service_offering');
}
}
Script Include (tick the Client callable box, make sure it's name matches the declaration on the first line below)
var CsdmRelationshipAjax = Class.create();
CsdmRelationshipAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getServiceFromOffering: function() {
var grServiceOffering = new GlideRecord('service_offering');
if(grServiceOffering.get(this.getParameter('sysparm_offering'))) {
var answer = {};
answer.serviceSysId = grServiceOffering.getValue('parent');
answer.displayValue = grServiceOffering.getDisplayValue('parent');
return JSON.stringify(answer);
}
},
type: 'CsdmRelationshipAjax'
});
Unfortunately ServiceNow has not provided any scripting support for negotiating CSDM Service relationships.
I have provided a Script Include to the community that traverses all common CSDM relationships server-side. If you use this then amend the script include function getServiceFromOffering above to be a wrapper function that simply passes the parameter to the server-side script function and receives the response. This keeps all the relevant logic in one place (server side script include).
I hope this helps!
Mat
