- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
Hi Everyone,
I have created a custom widget that displays a list of Incidents. Now, I want to show the variables (coming from a Record Producer) inside this widget as part of the list (e.g., as a column).
Currently:
The Incident record is also creating from Record Producer.
The variables submitted via the Record Producer are visible on the Incident form (at the bottom via Variable Editor).
However, these variables are not visible in the form layout and also not appearing in my custom widget.
What I need:
Display Record Producer variables (Variable Editor data) inside my custom widget (Incident list).
Ideally, show them as columns or part of each record output.
I have already:
Checked Form Layout but couldn’t find the Variable Editor field.
Tried searching for solutions but couldn’t figure out how to fetch/display variables in the widget.
This is my code for custom widget:
html:
<div class="incident-widget">
<h3>Incident List</h3>
<table class="incident-table">
<thead>
<tr>
<th>Number</th>
<th>Short Description</th>
<th>Priority</th>
<th>Assigned To</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="inc in data.incidents">
<td>{{inc.number}}</td>
<td>{{inc.short_description}}</td>
<td>
<span class="priority priority-{{inc.priority}}">
{{inc.priority}}
</span>
</td>
<td>{{inc.assigned_to}}</td>
</tr>
</tbody>
</table>
css:
.incident-widget {
padding: 15px;
background: #fff;
border-radius: 8px;
}
.incident-table {
width: 100%;
border-collapse: collapse;
}
.incident-table th {
background: #007bff;
color: white;
padding: 10px;
text-align: left;
}
.incident-table td {
padding: 10px;
border-bottom: 1px solid #ddd;
}
.incident-table tr:hover {
background-color: #f5f5f5;
}
/* Priority colors */
.priority-1 {
color: red;
font-weight: bold;
}
.priority-2 {
color: orange;
}
.priority-3 {
color: green;
}
.priority-4 {
color: blue;
}
client script:
function($scope) {
console.log("Incident widget loaded");
}
server script:
(function() {
data.incidents = [];
data.count = 0;
var gr = new GlideRecord('incident');
gr.addActiveQuery();
gr.orderByDesc('sys_created_on');
gr.setLimit(10);
gr.query();
while (gr.next()) {
data.incidents.push({
number: gr.getDisplayValue('number'),
short_description: gr.getDisplayValue('short_description'),
priority: gr.getDisplayValue('priority'),
assigned_to: gr.getDisplayValue('assigned_to') || 'Not Assigned'
});
}
data.count = data.incidents.length;
gs.info("Widget Incident Count: " + data.count);
})();
need to show'Optional Software (backend name: optional_software) and Additional software requirements (u_asr) variables as column in widget.
Thanks in Advance.
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
When a Record Producer targets the Incident table, the submitted values are not stored as columns on incident. They're stored in the variable pool — specifically across these tables:
item_option_new— variable definition (name, label, type)sc_item_option— the actual submitted valuesc_item_option_mtom— the link between the target record (your incident) and eachsc_item_option
That's why Form Layout doesn't list them as fields and why your current GlideRecord query returns nothing for them — they aren't dot-walkable as normal incident fields.
Fix: use gr.variables.<name> in the server script
The cleanest approach is the variables API on GlideRecord. It transparently resolves the variable pool for record-producer-created tasks. Update your server script like this:
(function() {
data.incidents = [];
data.count = 0;
var gr = new GlideRecord('incident');
gr.addActiveQuery();
gr.orderByDesc('sys_created_on');
gr.setLimit(10);
gr.query();
while (gr.next()) {
var optionalSoftware = '';
var additionalSoftware = '';
// Guarded access — only incidents created by a record producer will have these
if (gr.variables && gr.variables.optional_software) {
optionalSoftware = gr.variables.optional_software.getDisplayValue() || '';
}
if (gr.variables && gr.variables.u_asr) {
additionalSoftware = gr.variables.u_asr.getDisplayValue() || '';
}
data.incidents.push({
number: gr.getDisplayValue('number'),
short_description: gr.getDisplayValue('short_description'),
priority: gr.getDisplayValue('priority'),
assigned_to: gr.getDisplayValue('assigned_to') || 'Not Assigned',
optional_software: optionalSoftware,
additional_software: additionalSoftware
});
}
data.count = data.incidents.length;
})();
Why getDisplayValue() matters here: optional_software is a multi-checkbox/multi-row variable, so .value returns the raw sys_ids or internal values. getDisplayValue() returns the user-readable labels (comma-separated for multi-value).
Update the HTML to show the new columns
<div class="incident-widget">
<h3>Incident List</h3>
<table class="incident-table">
<thead>
<tr>
<th>Number</th>
<th>Short Description</th>
<th>Priority</th>
<th>Assigned To</th>
<th>Optional Software</th>
<th>Additional Requirements</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="inc in data.incidents">
<td>{{inc.number}}</td>
<td>{{inc.short_description}}</td>
<td>
<span class="priority priority-{{inc.priority}}">{{inc.priority}}</span>
</td>
<td>{{inc.assigned_to}}</td>
<td>{{inc.optional_software || '--'}}</td>
<td>{{inc.additional_software || '--'}}</td>
</tr>
</tbody>
</table>
</div>
Alternative: query sc_item_option_mtom directly
If gr.variables.<name> ever returns empty (can happen if the variables were attached via custom code rather than through a standard Record Producer submission), fall back to an explicit join:
function getIncidentVariables(incidentSysId) {
var out = {};
var mtom = new GlideRecord('sc_item_option_mtom');
mtom.addQuery('request_item', incidentSysId);
mtom.query();
while (mtom.next()) {
var opt = mtom.sc_item_option.getRefRecord();
if (!opt.isValidRecord()) continue;
var varName = opt.item_option_new.name.toString();
out[varName] = opt.getDisplayValue('value');
}
return out;
}
Then call var vars = getIncidentVariables(gr.getUniqueValue()); inside your loop and read vars.optional_software / vars.u_asr.
A couple of things to watch out for
- ACLs on
sc_item_option/sc_item_option_mtom— if portal users don't have read access to these tables,gr.variableswill come back empty even though the data exists. Check with a user who only has the Service Portal role. - Performance — you're already limiting to 10 records, which is fine. If you scale this up, the MTOM fallback approach can get expensive; stick with
gr.variableswhere possible. - Incidents not created via Record Producer — those won't have any variables, so the guarded
if (gr.variables.optional_software)check prevents null errors.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
hey @rah dev
Below script fetches
- optional_software (checkbox)
- u_asr (text)
Server side script
(function() {
data.incidents = [];
var gr = new GlideRecord('incident');
gr.addActiveQuery();
gr.orderByDesc('sys_created_on');
gr.setLimit(10);
gr.query();
while (gr.next()) {
var optionalSoftware = '';
var additionalReq = '';
// Fetch variables only if request_item exists
if (gr.request_item) {
var mtom = new GlideRecord('sc_item_option_mtom');
mtom.addQuery('request_item', gr.request_item);
mtom.query();
while (mtom.next()) {
var varName = mtom.sc_item_option.item_option_new.name.toString();
var varValue = mtom.sc_item_option.value.toString();
if (varName === 'optional_software') {
optionalSoftware += varValue + ', ';
}
if (varName === 'u_asr') {
additionalReq = varValue;
}
}
}
// Remove trailing comma
optionalSoftware = optionalSoftware.replace(/, $/, '');
data.incidents.push({
number: gr.getDisplayValue('number'),
short_description: gr.getDisplayValue('short_description'),
priority: gr.getDisplayValue('priority'),
assigned_to: gr.getDisplayValue('assigned_to') || 'Not Assigned',
optional_software: optionalSoftware,
u_asr: additionalReq
});
}
})();HTML Changes
Add new columns:
<th>Optional Software</th>
<th>Additional Requirements</th>Update row:
<td>{{inc.optional_software}}</td>
<td>{{inc.u_asr}}</td>
*************************************************************************************************************************************
If this response helps, please mark it as Accept as Solution and Helpful.
Doing so helps others in the community and encourages me to keep contributing.
Regards
Vaishali Singh
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
Thanks for the response.
But the issue is that there is a Record Producer which is creating an Incident record. Its Variable Editor has already been added to the Incident table form. Now, I want the variables from that Variable Editor to also appear as columns in the widget.
In your code, it is written that the variables will show if there is an RITM, but a Record Producer does not create an RITM. That’s why this script is not running.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
When a Record Producer targets the Incident table, the submitted values are not stored as columns on incident. They're stored in the variable pool — specifically across these tables:
item_option_new— variable definition (name, label, type)sc_item_option— the actual submitted valuesc_item_option_mtom— the link between the target record (your incident) and eachsc_item_option
That's why Form Layout doesn't list them as fields and why your current GlideRecord query returns nothing for them — they aren't dot-walkable as normal incident fields.
Fix: use gr.variables.<name> in the server script
The cleanest approach is the variables API on GlideRecord. It transparently resolves the variable pool for record-producer-created tasks. Update your server script like this:
(function() {
data.incidents = [];
data.count = 0;
var gr = new GlideRecord('incident');
gr.addActiveQuery();
gr.orderByDesc('sys_created_on');
gr.setLimit(10);
gr.query();
while (gr.next()) {
var optionalSoftware = '';
var additionalSoftware = '';
// Guarded access — only incidents created by a record producer will have these
if (gr.variables && gr.variables.optional_software) {
optionalSoftware = gr.variables.optional_software.getDisplayValue() || '';
}
if (gr.variables && gr.variables.u_asr) {
additionalSoftware = gr.variables.u_asr.getDisplayValue() || '';
}
data.incidents.push({
number: gr.getDisplayValue('number'),
short_description: gr.getDisplayValue('short_description'),
priority: gr.getDisplayValue('priority'),
assigned_to: gr.getDisplayValue('assigned_to') || 'Not Assigned',
optional_software: optionalSoftware,
additional_software: additionalSoftware
});
}
data.count = data.incidents.length;
})();
Why getDisplayValue() matters here: optional_software is a multi-checkbox/multi-row variable, so .value returns the raw sys_ids or internal values. getDisplayValue() returns the user-readable labels (comma-separated for multi-value).
Update the HTML to show the new columns
<div class="incident-widget">
<h3>Incident List</h3>
<table class="incident-table">
<thead>
<tr>
<th>Number</th>
<th>Short Description</th>
<th>Priority</th>
<th>Assigned To</th>
<th>Optional Software</th>
<th>Additional Requirements</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="inc in data.incidents">
<td>{{inc.number}}</td>
<td>{{inc.short_description}}</td>
<td>
<span class="priority priority-{{inc.priority}}">{{inc.priority}}</span>
</td>
<td>{{inc.assigned_to}}</td>
<td>{{inc.optional_software || '--'}}</td>
<td>{{inc.additional_software || '--'}}</td>
</tr>
</tbody>
</table>
</div>
Alternative: query sc_item_option_mtom directly
If gr.variables.<name> ever returns empty (can happen if the variables were attached via custom code rather than through a standard Record Producer submission), fall back to an explicit join:
function getIncidentVariables(incidentSysId) {
var out = {};
var mtom = new GlideRecord('sc_item_option_mtom');
mtom.addQuery('request_item', incidentSysId);
mtom.query();
while (mtom.next()) {
var opt = mtom.sc_item_option.getRefRecord();
if (!opt.isValidRecord()) continue;
var varName = opt.item_option_new.name.toString();
out[varName] = opt.getDisplayValue('value');
}
return out;
}
Then call var vars = getIncidentVariables(gr.getUniqueValue()); inside your loop and read vars.optional_software / vars.u_asr.
A couple of things to watch out for
- ACLs on
sc_item_option/sc_item_option_mtom— if portal users don't have read access to these tables,gr.variableswill come back empty even though the data exists. Check with a user who only has the Service Portal role. - Performance — you're already limiting to 10 records, which is fine. If you scale this up, the MTOM fallback approach can get expensive; stick with
gr.variableswhere possible. - Incidents not created via Record Producer — those won't have any variables, so the guarded
if (gr.variables.optional_software)check prevents null errors.
