- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-28-2020 10:20 AM
Hi,
On the Change request we see Add Button which triggers a ui page which is not visible for the users.
Is there anyway we can create a similar functionality on custom table ?
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-30-2020 08:01 PM
From your use case, my understanding is the the KPI will be linked to the Performance Management record using a many to many relationship. Would a simple many to many definition (sys_m2m) do the job? It would add an edit button on that created relatinship (related list) to allow to link one or many KPI to be linked to the Performance Mangement record.
If you really wish to have a modal window to complete this, I have done something like that in the past. It is a custom UI page that is loading a list based on a table query and allows to select rows to then apply an action to these rows. So it is similar to the Add Selected option of the Impacted CIs. However it does not allow to search or select a table, therefore it only fits a use case with a small amount of options.
Here is the info of that custom page. I did modify the script to post it, so there may be bugs since it is untested.
Name: select_list
Description:
Parameters:
sysparm_description_text: Description, the text is passed into gs.getMessage for translation purpose
sysparm_table: table to query
sysparm_query: encoded query
sysparm_fields: comma seperated list of fields to be included
sysparm_selected_query: encoded query of record to be pre-selected
HTML:
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<g:evaluate object="true">
var gr = new GlideRecordSecure(RP.getParameterValue('sysparm_table'));
gr.addEncodedQuery(RP.getParameterValue('sysparm_query'));
gr.query();
</g:evaluate>
<g:evaluate>
var selectedQuery = RP.getParameterValue('sysparm_selected_query') || '';
selectedQuery = GlideStringUtil.unEscapeHTML(selectedQuery);
</g:evaluate>
<j:set var="jvar_fields" value="${RP.getParameterValue('sysparm_fields').split(',')}" />
<g:evaluate object="true" jelly="true" var="jvar_field_labels">
//Set field labels
var fieldLabels = jelly.jvar_fields.map(function(field){
return new DotWalkingHelper(gr, field).getLabel();
});
fieldLabels;
</g:evaluate>
<j:set var="jvar_fields" value="${RP.getParameterValue('sysparm_fields').split(',')}" />
<style>
/* dialog styles */
.dialog_buttons {
text-align: right;
vertical-align:bottom;
white-space: nowrap;
padding-right: 15px;
}
tr.dialog_spacer {
height: 8px;
}
#content_row .reference-label {
padding-right: 15px;
}
.row{
padding-left: 15px;
}
</style>
<!-- Set up form fields and labels -->
<table width="100%" id="select_list">
<tr class="dialog_spacer"></tr>
<tr>
<p>${gs.getMessage(RP.getParameterValue('sysparm_description_text'))}</p>
</tr>
<tr id="content_row" valign="top">
<td>
<table class="table table-hover list_table">
<thead>
<tr>
<th></th>
<j:forEach items="${jvar_field_labels}" var="jvar_field_label">
<th>${jvar_field_label}</th>
</j:forEach>
</tr>
</thead>
<tbody>
<j:while test="${gr.next()}">
<g:evaluate>
var rowClass = gr.getLocation() % 2 == 0 ? 'list_odd' : 'list_even';
</g:evaluate>
<g:evaluate>
var checked = false;
if(selectedQuery){
var gf = new GlideFilter(selectedQuery, '');
gf.setCaseSensitive(false);
checked = gf.match(gr, true);
}
</g:evaluate>
<tr class="list_row ${rowClass}" id="select_list_${gr.getUniqueValue()}">
<td class="list_decoration_cell col-control col-small col-center" style="white-space:nowrap;">
<span class="input-group-checkbox">
<j:choose>
<j:when test="${checked}">
<input type="checkbox" id="select_list_check_${gr.getUniqueValue()}" class="checkbox" checked=""/>
</j:when>
<j:otherwise>
<input type="checkbox" id="select_list_check_${gr.getUniqueValue()}" class="checkbox" />
</j:otherwise>
</j:choose>
<label for="select_list_check_${gr.getUniqueValue()}" class="checkbox-label"></label>
</span>
</td>
<j:forEach items="${jvar_fields}" var="jvar_field">
<g:evaluate jelly="true">
var displayValue = new DotWalkingHelper(gr, jelly.jvar_field).getDisplayValue();
</g:evaluate>
<td class="vt">${displayValue}</td>
</j:forEach>
</tr>
</j:while>
</tbody>
</table>
</td>
</tr>
<tr class="dialog_spacer"></tr>
<tr>
<td class="dialog_buttons" colspan="2">
<g:dialog_buttons_ok_cancel ok="dialogSelectList.completed()"
ok_text="${gs.getMessage('Save')}"
cancel="dialogSelectList.actionCancel();" cancel_type="button"/>
</td>
</tr>
</table>
</j:jelly>
Client Script:
//Create object for page to avoid scope issue when loaded in modal window
var dialogSelectList = {
actionCancel: function(){
var gdw = GlideDialogWindow.get();
var f = gdw.getPreference('onPromptCancel');
if (typeof(f) == 'function') {
try {
f.call(gdw, gdw.getPreference('oldValue'));
} catch(e) {
}
}
else
gdw.destroy();
},
completed: function(){
var gdw = GlideDialogWindow.get();
var f = gdw.getPreference('onPromptComplete');
if (typeof(f) == 'function') {
try {
f.call(gdw, this.getCheckedSysIds(), this.getNotCheckedSysIds());
} catch(e) {
console.log(e);
}
}
else
gdw.destroy();
},
getCheckedSysIds: function(){
var checked = $j('#select_list input:checked');
var ids = checked.toArray().map(function(check){
var checkSplit = check.id.split('_');
return checkSplit[checkSplit.length -1];
});
return ids;
},
getNotCheckedSysIds: function(){
var notChecked = $j('#select_list input:not(:checked)');
var ids = notChecked.toArray().map(function(check){
var checkSplit = check.id.split('_');
return checkSplit[checkSplit.length -1];
});
return ids;
}
};
This UI page as a dependency on a custom script include to work with DotWalking.
Name: DotWalkingHelper
Script:
var DotWalkingHelper = Class.create();
DotWalkingHelper.prototype = {
initialize: function(gr, dotWalkinkString) {
this.element = this._getElement(gr, dotWalkinkString);
},
getLabel: function(){
if(typeof this.element == 'undefined'){
return '';
}
else{
return this.element.getLabel();
}
},
getValue: function(){
if(typeof this.element == 'undefined'){
return '';
}
else{
return this.element.toString();
}
},
getDisplayValue: function(){
if(typeof this.element == 'undefined'){
return '';
}
else{
return this.element.getDisplayValue();
}
},
getType: function(){
if(typeof this.element == 'undefined'){
return '';
}
else{
return this.element.getED().getInternalType();
}
},
_getElement: function(gr, dotWalkinkString){
var fieldSplit = j2js(dotWalkinkString).split('.');
var field = fieldSplit[0];
if(!gr.isValidField(field)){
return;
}
var element = gr[field];
for(var x=1; x<fieldSplit.length; x++){
if(typeof element[fieldSplit[x]] == 'undefined'){
//Support to dot walk for system user field (sys_created_by, sys_updated_by)
if(element.getName() == 'sys_created_by' || element.getName() == 'sys_updated_by'){
var user = new GlideRecord('sys_user');
if(user.get('user_name', element.toString())){
if(typeof user[fieldSplit[x]] == 'undefined')
return;
element = user[fieldSplit[x]];
}
else
return;
}
else
return;
}
else
element = element[fieldSplit[x]];
}
return element;
},
type: 'DotWalkingHelper'
};
Then the UI page is called by a Client side UI Action. You can pass a callback function to the UI page and the function will be called with the checked and unchecked elements of the list. From there you can use a GlideAjax call to make the required inserts/updates. Here is a snippet of the usage of the UI page.
var dialogClass = window.GlideModal ? GlideModal : GlideDialogWindow;
var gDialog = new dialogClass("select_list");
gDialog.setTitle(getMessage('Select device'));
gDialog.setPreference('sysparm_description_text', 'message.text');
gDialog.setPreference('sysparm_table', 'cmdb_ci_computer');
gDialog.setPreference('sysparm_query', 'assigned_to=' + g_form.getUniqueValue());
gDialog.setPreference('sysparm_fields', 'name,model_id,model_id.type');
gDialog.setPreference('sysparm_selected_query', 'assigned_to=' + g_form.getUniqueValue());
gDialog.setPreference('onPromptComplete', function(checked, unchecked){
var ga = new GlideAjax('CMDBGroup');
ga.addParam('sysparm_name', 'addAndRemoveCIsFromGroup');
ga.addParam('sysparm_group_id', WORKSTATION_PILOT_GROUP);
ga.addParam('sysparm_added_cis', checked.join(','));
ga.addParam('sysparm_removed_cis', unchecked.join(','));
ga.getXMLAnswer(function(answer){
if(g_form.getActionName() == 'sysverb_update'){
g_form.submit();
}
else{
g_form.save();
}
});
});
gDialog.render();

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-28-2020 10:41 AM
Hi Irfan,
Yes, you can. You can check for System Definitions >> UI Actions & then filter by name Add
Look for the on the Impacted CIs table. Disable the same & check the difference. There is a code that calls script include something similar can be done for your business case depending on the need.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-28-2020 11:12 AM
That script include calls the ui page which is not visible sir.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-28-2020 12:58 PM
Hi Irfan,
I thought the initial request was to create a separate page which still you can by creating UI Page & then add required logic as per business need.
Anyways, page: task_add_affected_cis is not accessible & doc link states the same.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-28-2020 02:24 PM
Follow below solution which has UI action code to open UI page from list.
Regards,
Sachin