Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
api.controller=function($scope, $http, spUtil, $rootScope, $timeout, spModal) {
/* widget controller */
var c = this;

// Initialize scope variables
$scope.tablename = {
displayValue: '',
value: '',
name: 'tablename'
};
$scope.record = {
displayValue: '',
value: '',
name: 'record'
};
$scope.selectedTable = '';
$scope.TableSysId = '';

// Handle field changes (table/record)
$scope.$on("field.change", function(evt, parms) {
if (parms.field.name === 'tablename') {
// Get sys_id of selected table → fetch actual table name & label
var sysId = parms.newValue;
var url = '/api/now/table/sys_db_object/' + sysId + '?sysparm_fields=name,label';
$http.get(url).then(function(res) {
if (res.data.result) {
$scope.selectedTable = res.data.result.name;
$scope.selectedTableLabel = res.data.result.label;
c.getDisplayField($scope.selectedTable, sysId); // fetch display field
}
});
} else if (parms.field.name === 'record') {
// Save selected record sys_id
$scope.TableSysId = parms.newValue;
}
});

// Get display field for a table (recursive if needed)
c.getDisplayField = function(tableName, tablesysId) {
var url = '/api/now/table/sys_dictionary' +
'?sysparm_query=name=' + tableName + '^display=true' +
'&sysparm_fields=element' +
'&sysparm_limit=1';

$http.get(url).then(function(response) {
if (response.data.result && response.data.result.length > 0) {
// Found display field
$scope.recorddisplayValue = response.data.result[0].element;
} else {
// Check parent table
var parentsysIdUrl = '/api/now/table/sys_db_object/' + tablesysId + '?sysparm_fields=super_class';
$http.get(parentsysIdUrl).then(function(parentRes) {
var parentTable = parentRes.data.result.super_class.value;

if (!parentTable) {
// No parent - fallback checks
var nameCheckUrl = '/api/now/table/sys_dictionary' +
'?sysparm_query=name=' + tableName + '^element=name' +
'&sysparm_fields=element&sysparm_limit=1';

$http.get(nameCheckUrl).then(function(nameRes) {
if (nameRes.status == 200) {
$scope.recorddisplayValue = 'name';
} else {
var numberCheckUrl = '/api/now/table/sys_dictionary' +
'?sysparm_query=name=' + tableName + '^element=number' +
'&sysparm_fields=element&sysparm_limit=1';

$http.get(numberCheckUrl).then(function(numberRes) {
if (numberRes.status == 200) {
$scope.recorddisplayValue = 'number';
} else {
$scope.recorddisplayValue = 'sys_id'; // Final fallback
}
});
}
});

} else {
// Parent exists - recurse
var parentNameUrl = '/api/now/table/sys_db_object/' + parentTable + '?sysparm_fields=name';
$http.get(parentNameUrl).then(function(parentResname) {
var parentTableName = parentResname.data.result.name;
c.getDisplayField(parentTableName, parentTable); // recursive lookup
});
}
});
}
}, function(error) {
spModal.alert("Error fetching display field: " + error);
});
};

};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<div class="row">
<div class="col-md-6">
<label class="form-label">Select Table</label>
<sn-record-picker
field="tablename"
table="'sys_db_object'"
display-field="'label'"
value-field="'sys_id'"
search-fields="'label'"
page-size="100">
</sn-record-picker>
</div>

<!-- After a table is chosen, show record selector -->
<div class="col-md-6" ng-show="selectedTable && recorddisplayValue">
<label class="form-label">Select Record</label>
<sn-record-picker
field="record"
table="selectedTable"
display-field="recorddisplayValue"
value-field="'sys_id'"
search-fields="recorddisplayValue"
page-size="100">
</sn-record-picker>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
Widget Name: Dynamic Table and Record Selector

Overview:
This ServiceNow Service Portal widget allows users to dynamically select any table and then choose a record from that table. The widget automatically determines which field should be shown as the display field for the selected table. It also handles parent table inheritance and provides fallback options for display fields.

Main Features:

Lists all tables from the sys_db_object table.

Automatically finds the correct display field (field with display=true).

Supports parent table lookup if the child table does not have a display field.

Provides fallback checks for fields named "name", "number", or defaults to "sys_id".

Uses ServiceNow REST APIs to fetch metadata and record data dynamically.

Works with the standard sn-record-picker directive in Service Portal.

How It Works:

The first record picker displays all tables from sys_db_object using the label field.

When the user selects a table, the widget fetches the actual table name and label using the sys_id.

The controller calls the getDisplayField function to determine which field should be displayed in the record picker.

It checks sys_dictionary for a field with display=true.

If found, that field is used as the display field.

If not found, it checks if the table has a parent (super_class).

If a parent exists, it recursively checks the parent table.

If there is no parent, it uses fallback checks for "name", then "number", and finally "sys_id".

The second record picker then displays the records from the selected table using the determined display field.

When the user selects a record, its sys_id is stored in the variable TableSysId.

Example Flow:

Select “Incident” from the table picker.

The widget detects that the display field is “number”.

The record picker lists incident numbers.

When a record is selected, its sys_id is saved for further use.

Technologies Used:

ServiceNow Service Portal

AngularJS (spUtil, spModal)

ServiceNow REST API:

/api/now/table/sys_db_object

/api/now/table/sys_dictionary

Use Cases:

Creating dynamic reference selectors for any table.

Building tools that link or map data between tables.

CMDB record selection where tables may have inheritance.

Generic admin utilities or catalog forms needing flexible input.

File Components:

HTML Template: Contains two sn-record-picker elements for selecting table and record.

Client Controller (JS): Handles field change events, fetches table metadata, determines display fields, and manages recursion logic.
Loading