- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎09-25-2015 04:55 AM
Im sorry to ask again but need help and also need to learn how to script this demand.
I can find way how to populate service on incident form if SD user select last appllication on the image below - 3
I havent luck to buil onchange client script - Im able to build script which returns me only direct relation ( from 3 to 2 ) but not what we need ( from 3 to X)
would somebody give me a lesson here please ? Please note that I need onchange solution, so service is prefilled always when suer change CI
My system fields are
cmdb_ci -- for apps
u_service_ci -- for service
thank you
/Petr
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-01-2015 07:22 AM
Hi Petr,
Nice work on the GlideAjax script. I do have a few recommendations that can improve your script and hopefully help you learn a little more about GlideAjax in the process (you can also check out my infographic on GlideAjax for additional info: Demystifying GlideAjax).
So first, the scripts (please bear in mind I haven't fully tested these yet so they may need some tweaks):
Client Script
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue == '') {
return;
}
var ooo = g_form.getValue('cmdb_ci'); // this is the sys id of CI entered by user
var ga = new GlideAjax('BusinessServiceFinder');
ga.addParam('sysparm_name', 'getServiceForCI');
ga.addParam('sysparm_ci_sys_id', ooo); // passing CI sys_id to script include
ga.getXML(setBusinessService);
function setBusinessService(response) {
var answer = response.responseXML.documentElement.getAttribute('answer');
g_form.setValue('u_service_ci', answer); // get answer from Script Include and set Service CI field
alert(answer);
}
}
Script Include
var BusinessServiceFinder = Class.create();
BusinessServiceFinder.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getServiceForCI: function() {
var this_is_variable_from_form = this.getParameter('sysparm_ci_sys_id') + '';
return this._getParentRelationship(this_is_variable_from_form);
},
_getParentRelationship: function(ciSysId) {
var o = new GlideRecord('cmdb_rel_ci');
o.addQuery('child', ciSysId);
o.query();
if (o.next()) {
if (o.parent.sys_class_name == 'cmdb_ci_service') {
return o.getValue('parent'); // return the CI's sys_id
}
else {
return this._getParentRelationship(o.getValue('parent')); // recursively execute the function for the parent's sys_id
}
}
else {
return 'There is no direct relation to service';
}
},
type: 'BusinessServiceFinder'
})
Changes
1. You will notice that I changed the names of the Script Include and its function. You can change these names as you desire, but with GlideAjax there is a convention that you must follow:
- The name of the Script Include (BusinessServiceFinder) must be included inside the parenthesis of the GlideAjax call as shown on line 7 of the Client Script. This tells GlideAjax which Script Include to use.
- The name of the Script Include's function (getServiceForCI) must be included in the Client Script by setting it as the sysparm_name parameter as shown on line 8 of the Client Script.
2. You will also notice that I added a private function _getParentRelationship and changed the getServiceForCI function to use it. The _getParentRelationship is a recursive function that calls itself. This eliminates the need for the nested if statements and reduces the duplicated code. Basically, the _getParentRelationship function will keep calling itself by passing the parent CI in the relationship until it finds a Business Service or is unable to find a relationship. The advantage in this script is that it will work for any sized relationship tree depth. If you were to at some point in the future link relationships 6 nodes from the Business Service, this script will still work.
I hope this helps. And thank you deepak.ingale for looping me in!
Kind regards,
Travis
EDIT: A few typos, missing punctuation, wrong punctuation, and other miscellaneous errors later, this script has now been tested. Thanks guys!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-01-2015 06:58 PM
Hi Travis works great now...thank you for explaining the components involved!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-03-2015 08:41 AM
Hi Travis, was trying to use the same logic in a business rule its working as expected, would like you know you expert opinion. In here instead of returning the string back i updated the current record from the script include itself
Business Rule:
function onAfter(current, previous) {
var sbrq = new BusinessServiceFinder();
sbrq.getServiceForCI();
}
Script Include:
var BusinessServiceFinder = Class.create();
BusinessServiceFinder.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getServiceForCI: function() {
var this_is_variable_from_form = current.cmdb_ci;
return new JSON().encode(this._getParentRelationship(this_is_variable_from_form));
},
_getParentRelationship: function(ciSysId) {
var o = new GlideRecord('cmdb_rel_ci'),
businessServices = [];
o.addQuery('child', ciSysId);
o.query();
while (o.next()) {
if (o.parent.sys_class_name == 'cmdb_ci_service') {
businessServices.push(o.getValue('parent')); // add the CI's sys_id to the return array
}
else {
businessServices = businessServices.concat(this._getParentRelationship(o.getValue('parent'))); // recursively execute the function for the parent's sys_id and join the returned businessServices array to the current array
}
}
var answernew = businessServices.join(',');
current.u_business_service_list =answernew;
current.update();
return businessServices;
},
type: 'BusinessServiceFinder'
})
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-03-2015 09:18 AM
Hi Mathew,
Glad to hear its working for you! Your modifications look good. The one thing I will point out is that with a reference to current directly inside the Script Include, the Script Include can no longer be easily reused. The Script Include is tightly coupled to the table and server side implementation. This is not a problem, there is nothing intrinsically wrong with that approach, but you will find your scripts will be easier to test, troubleshoot, and repurpose if you establish a single responsibility for each script and maintain looser coupling. In this case, I would divide up the responsibilities like this:
Business Rule: Manages the current record
Script Include: Retrieves an Array of parent Business Services for a given CI sys_id
The cool part is that if you look at my original Script Include, it is structured to be as reusable as possible:
BusinessServiceFinder.getServiceForCI: Brokers GlideAjax calls from the client to the BusinessServiceFinder functions
BusinessServiceFinder._getParentRelationship: Purely server side call that retrieves an array of parent Business Services for a given CI sys_id
I structure all of my GlideAjax script includes this way. I have one function that is client callable and one that is server callable where the server callable performs all the real work and the client callable just brokers the AJAX parameters and response. This allows me to use and test the Script Include easily from the server without requiring the GlideAjax client setup. In your case, you could use the Script Include as is in the Business Rule like so:
function onBefore(current, previous) {
var sbrq = new BusinessServiceFinder();
var businessServices = sbrq._getParentRelationship(current.cmdb_ci);
current.u_business_service_list = businessServices.join(',');
}
You will also notice that I changed it to a onBefore. Since you are updating the current record, it is usually best to perform these before insert/update so that you aren't duplicating updates.
I hope this helps.
Kind regards,
Travis
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-03-2015 06:32 PM
Bravo!...Thanks Travis
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎01-29-2020 11:25 PM
Hi
I am using your script to get all parent CI where the class is application and populating IT sytem owner from those parent Ci to the child glide list field and it is working when there is any insert of record in cmd_rel_ci Table.
I got challenge when i am trying to have it in a Fix script where we have 45k Cmdb relations. when i run this script its not working i am not sure is it due to array limitations or due to any recursive loops.
Can you please help here how to complete this requirement to update all the existing ci in a fix script.
Thanks