- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-02-2021 10:24 AM
I have been working on several on-change client scripts to make this work, but have so far been unsuccessful. The task to make two fields that share the same table populate with their respective values, based-on the value of another field from the same table.
Below, is my script include.
How do I go about writing an on-change CS to make this work?
Thank you!
Solved! Go to Solution.
- Labels:
-
Scripting and Coding
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-02-2021 03:41 PM
This is what I have defined in my PDI:
HHave added the fields to the Change Request form:
After flushing the cache, when I change System, Analyst and Owner automatically update.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-31-2021 07:23 AM
Thanks for the response!
I've had another minor setback. It was determined a product owner table already exists and we should stick to it, instead of creating a second custom table to manage.
Unfortunately, since that table is an extension of the product table, it won't allow me to use it for data lookups, since it needs to extend the dl_matcher table to do so.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-31-2021 08:14 AM
The question is how live should this be? If it is not a problem to fill in the data upon saving the form, you could create a Flow or a Business Rule - you can get away with no scripting.
If however you want this to happen live on the form as users change the system, you need to set up an Ajax call, meaning you need a Script Include (to handle the server side logic) and an on-change Client Script (to handle the client logic).
What you have at the beginning of the question is a mixture of what is valid on the server side and what is valid on the client side. I have very recently written a reply in question Portal - from a Task, get parent Case details where I try to explain how to use GlideAjax. I encourage you to read it and try to come up with the solution. But if you still have question, just let it be known - I'll to my best to answer.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-31-2021 09:16 AM
Thanks for the reply!
Upon reading your response, I came up with something like this for the CS:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var sn = g_form.getValue('System');
var ga = new GlideAjax('GetSysName'); // Script Include Name
ga.addParam('sysparm_name', 'getName'); // SI Method
ga.addParam('sysparm_system_name', sn); // Parameter for SI
ga.getXMLAnswer(function(response)
{
alert('answer is '+answer);
g_form.setValue('u_system_owner',answer[0]);
g_form.setValue('u_analyst',answer[1]);
});
}
And for the SI:
GetRequestedByData.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getName:function(){
var gn = [];
var sn = this.getParameter('sysparm_system_name');
var rec = new GlideRecord('cmdb_application_product_model');
if(rec.get(sn)){
gn.push(rec.owner);
gn.push(rec.u_analyst);
}
return gn;
},
type: 'GetSysName'
});
Where "Owner" on the Product table is u_system_owner on the CR table.
Is this on the right track?
Also, this doesn't need to display Live, it just needs to be visible after the initial update (since both the Owner and Analyst fields are used to assign tasks, thereafter).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-31-2021 11:49 AM
Well, APIs in SN 99% of the time are designed to work with "internal" identifiers, not visible/display identifiers. Furthermore of those table and field names are always lower case. This is important because JavaScript is case sensitive. Thus the statement
var sn = g_form.getValue('System');
cannot be correct. System is most likely the label of the field while its name is probably u_system - well if we consult your screenshots, it is for sure. Because all field names are lower case and all custom fields in the global scope have the prefix u_.
Thus the correct statement would be:
var sn = g_form.getValue('u_system');
However this is not necessary as the value is readily available in one of the function's parameters - newValue, this Client Script being set to fire when u_system (System) changes.
As mentioned before, 99% of APIs work with internal values, so don't send the system's name with the Ajax request. The only time and place to use (so called) display values, is when showing something to the user. Other than that you should use internal names and values. In your case however the code and naming is misleading, as g_form.getValue() will get you an internal value (the sys_id or the unique value) and not the name - I'm talking about sysparm_system_name. I correct naming would be sysparm_system_id, sysparm_system_sys_id or sysparm_system_unique_value.
Another problem with the Client Script is that the answer received from the server (response) is nowhere written into variable answer. You should convert the string response into the array answer either with the help of JSON or String.prototype.split().
As for the Script Include, you try to refer to it with one name in the Client Script (GetSysName) but you define it with another name (GetRequestedByData). It should be the same name. Also I bet the field name is u_owner (also judging by your screen shots) and not owner. You should also control how the array you are building is serialized (turned into a string). You should use either JSON.stringify or .join(',').
Note that the statement
gn.push(rec.owner);
is not adding the value in field owner (which should be u_owner) to the array, but an object of type GlideElement. To make sure you are adding the value in that field, you need to extract the value from that object and one does that by coercing the object into a string, either by concatenating it with an empty string or calling the .toString() method of that object:
gn.push('' + rec.owner);
// or
gn.push(rec.owner + '');
// or
gn.push(rec.owner.toString());
// or
gn.push(String(rec.owner));
Of course in a final working code using the correct field name - u_owner.
As a general note, for optimization purposes and to obtain a better user experience, as I noted in the other article, you should be sending back to the browser, not only the sys_id of the Owner and the Analyst, but the display values also (the names).
I suppose the corrected final solution would be something like:
- the Script Include:
GetSysName.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getName: function () {
var gn = [];
var sn = this.getParameter('sysparm_system_unique_value');
var rec = new GlideRecord('cmdb_application_product_model');
if (rec.get (sn)) {
gn.push('' + rec.u_owner);
gn.push('' + rec.u_analyst);
}
return gn.join(',');
},
type: 'GetSysName'
});
- the Client Script:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var ga = new GlideAjax('GetSysName'); // Script Include Name
ga.addParam('sysparm_name', 'getName'); // SI Method
ga.addParam('sysparm_system_unique_value', newValue); // Parameter for SI
ga.getXMLAnswer(function (response) {
alert('response is ' + response);
var answer = response.split(',');
g_form.setValue('u_owner', answer[0]);
g_form.setValue('u_analyst', answer[1]);
});
}
I'm not sure which screen-shot in the end contains the correct field names, so do check those to be correct.
Another more optimized solution, which "saves" two asynchronous calls back to the server (after you set Owner and Analyst) to fetch the names (display values):
- the Script Include (notice I'm declaring gn as an object):
GetSysName.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getName: function () {
var gn = {};
var sn = this.getParameter('sysparm_system_unique_value');
var rec = new GlideRecord('cmdb_application_product_model');
if (rec.get(sn)) {
gn.owner = {
'uniqueValue': '' + rec.u_owner,
'displayValue': rec.u_owner.getDisplayValue(),
};
gn.analyst = {
'uniqueValue': '' + rec.u_analyst,
'displayValue': rec.u_analyst.getDisplayValue(),
};
}
return JSON.stringify(gn);
},
type: 'GetSysName'
});
- the Client Script:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var ga = new GlideAjax('GetSysName'); // Script Include Name
ga.addParam('sysparm_name', 'getName'); // SI Method
ga.addParam('sysparm_system_unique_value', newValue); // Parameter for SI
ga.getXMLAnswer(function (response) {
alert('response is ' + response);
var answer = JSON.parse(response);
g_form.setValue('u_owner', answer.owner.uniqueValue, answer.owner.displayValue);
g_form.setValue('u_analyst', answer.analyst.uniqueValue, answer.analyst.displayValue);
});
}
Again do check and correct field names where necessary.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-31-2021 03:03 PM
Wow - this is more information than what I could have ever asked for! Thank you!
I guess my confusion still comes from the field name for Owner. On the Product Application table, the owner field is named "owner" and is extended from the Product table. On the Change Request table however, it is u_system_owner, which references the Owner field on the Product Application table.
Don't these two fields have to be the same name? In other words, you're looking at the "owner" field in the SI and trying to display it for "u_system_owner" on the change request side.
I apologize if I'm just not getting it, but I do appreciate the help and better understanding.