relation, populate service from CI, cmdb_rel_ci

Pastupe
Mega Guru

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

1a.jpg

1 ACCEPTED SOLUTION

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!


View solution in original post

36 REPLIES 36

That work greatly!


HI Travis,



Thank you for providing this excellent code. I am new to ServiceNow and am currently setting up our instance. I have tried implementing the client script and script include but they do not seem to be working. Can you tell me what 'u_service_ci' is in your code? Is this a custom column added to the cmdb_ci table? We have the 'business_service' field on our Incident form, which is what we are trying to populate when a particular CI is entered on the form. I tried changing the client script to g_form.setValue('business_service', answer); but that did not work.



Hopefully you can send me on the right track.



Thanks!



Steve


Hi Steve,



Welcome to the platform!   Yes, in this case the u_service_ci is a custom field that is specific to Petr's requirements.   The set of scripts here also has a number of assumptions not explicitly documented here but you will want to check.   In your case:



1.   business_service field appears on the form you attach the Client Script to (it can be hidden)


2.   cmdb_ci field appears on the form you attach the Client Script to (it can be hidden)


3.   The script include has the "Client" checkbox marked (I think thats the name of it)


4.   The parent - child relationships are encoded in the cmdb_rel_ci table, not on a field on the cmdb_ci table



For item 4, to clarify, the relationship is established by a separate M2M table.   So you have cmdb_ci <= cmdb_rel_ci => cmdb_ci.



So check those items in your instance first.   If that doesn't work, let me know a bit about the table structure you are using.   Also, check for errors in the browser and the ServiceNow System Log and let me know if you see any issues in there.   Unfortunately, any time you are working with GlideAjax there are many places for potential errors to slip in.


Thanks Travis for the welcome and quick reply!



To answer the list:



1. The Business Service field is indeed present and visible on the Incident form (we may leverage this code in other places but for now its on Incident where we have the Client Script set up).


2. The cmdb_ci field is present and visible on the Incident form. What we are trying to do is have the user populate this field, then have the script populate the related Business Service.


3. The 'Client' box is checked on the Script Include.


4. We do have the CI to Business Service relationships established already, via the out of the box relationship tool. Right now they are one-to-one but this may change.



So should the tweak I made work in this case? (g_form.setValue('business_service', answer);) It does not seem to currently.



Another method I was exploring, since we may end up having more than one Business Service associated with a CI, was to only allow the Business Service field to have related services as pickable options, once a particular CI is populated on the form. E.g. only 'Account Management', and 'Email and Collaboration' would be available Business Services if Office 365 was picked as the CI. Would a way to implement this be to make the Business Service field a dependent field on CI?



Thanks,



Steve


Hi Steve,



Conceptually, it sounds like the change you made should have worked.   If you want to continue troubleshooting, the next step I would take is to add some logging statements in both the Client and Server scripts to find out where the disconnect is happening.



For the other approach you are talking about, you could add a reference qualifier to your Business Service field.   A dependent field might work as well but Ref Quals tend to be more flexible.