Skip to content

Commit 077e4f5

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into add-context-aware-va-topics
2 parents 7b39f0b + 5204396 commit 077e4f5

File tree

194 files changed

+7510
-101
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

194 files changed

+7510
-101
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
var GetRecentRequestValues = Class.create();
2+
GetRecentRequestValues.prototype = Object.extendsObject(AbstractAjaxProcessor, {
3+
getValues: function() {
4+
var userID = this.getParameter('sysparm_user');
5+
var itemID = this.getParameter('sysparm_item');
6+
var result = { found: false, values: {} };
7+
8+
var gr = new GlideRecord('sc_req_item');
9+
gr.addQuery('requested_for', userID);
10+
gr.addQuery('cat_item', itemID);
11+
gr.orderByDesc('sys_created_on');
12+
gr.setLimit(1);
13+
gr.query();
14+
15+
if (gr.next()) {
16+
result.found = true;
17+
18+
19+
var vars = gr.variables;
20+
result.values = {
21+
'requested_for': vars.requested_for + '',
22+
'location': vars.location + '',
23+
'department': vars.department + ''
24+
};
25+
}
26+
27+
return JSON.stringify(result);
28+
}
29+
});
30+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
function onLoad() {
2+
var user = g_user.userID;
3+
var itemID = g_form.getUniqueValue();
4+
5+
var ga = new GlideAjax('GetRecentRequestValues');
6+
ga.addParam('sysparm_name', 'getValues');
7+
ga.addParam('sysparm_user', user);
8+
ga.addParam('sysparm_item', itemID);
9+
ga.getXMLAnswer(function(response) {
10+
var data = JSON.parse(response);
11+
if (data && data.found) {
12+
var confirmFill = confirm("We found a similar request. Do you want to autofill fields?");
13+
if (confirmFill) {
14+
for (var field in data.values) {
15+
if (g_form.getControl(field)) {
16+
g_form.setValue(field, data.values[field]);
17+
console.log("Set " + field + " to " + data.values[field]);
18+
} else {
19+
console.log("Field not found: " + field);
20+
}
21+
}
22+
}
23+
} else {
24+
console.log("No previous request found.");
25+
}
26+
});
27+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Recent Request Autofill for ServiceNow Catalog.it automatically offers to fill in fields based on the user's most recent similar request.
2+
Features
3+
- Detects previous requests for the same catalog item
4+
- Prompts user to reuse values from their last submission
5+
- Autofills fields like location, department, and justification
6+
7+
<img width="878" height="395" alt="image" src="https://github.com/user-attachments/assets/33ceabf5-2bbc-43e3-8792-f1f9a99699d2" />
8+
9+
10+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# MRVS - Normalise and Reset Rows on Change
2+
3+
## What this solves
4+
When a controlling variable changes (for example, Environment), existing MRVS rows may no longer be valid. This client script:
5+
- Clears or normalises specific MRVS columns
6+
- Deduplicates rows
7+
- Optionally sorts rows for a cleaner UX
8+
- Works entirely client-side using MRVS JSON
9+
10+
## Where to use
11+
Catalog Item → OnChange client script on your controlling variable.
12+
13+
## How it works
14+
- Reads the MRVS value as JSON via `g_form.getValue('my_mrvs')`
15+
- Applies transforms (clear columns, unique by key, sort)
16+
- Writes back the JSON with `g_form.setValue('my_mrvs', JSON.stringify(rows))`
17+
18+
## Setup
19+
1. Replace `CONTROLLING_VARIABLE` with your variable name.
20+
2. Replace `MY_MRVS` with your MRVS variable name.
21+
3. Adjust `COLUMNS_TO_CLEAR`, `UNIQUE_KEY`, and `SORT_BY` as needed.
22+
23+
## Notes
24+
- To clear the MRVS entirely, set `rows = []` before `setValue`.
25+
- Works with Catalog Client Scripts; no server call required.
26+
27+
## References
28+
- GlideForm API (client): `getValue`, `setValue`, `clearValue`
29+
https://www.servicenow.com/docs/bundle/zurich-api-reference/page/app-store/dev_portal/API_reference/GlideForm/concept/c_GlideFormAPI.html
30+
- Working with MRVS values on the client (community examples)
31+
https://www.servicenow.com/community/developer-articles/accessing-multi-row-variable-set-value-outside-the-multi-row/ta-p/2308876
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading) return;
3+
4+
var MRVS_NAME = 'MY_MRVS'; // your MRVS variable name
5+
var COLUMNS_TO_CLEAR = ['env', 'owner']; // MRVS column names to clear
6+
var UNIQUE_KEY = 'hostname'; // MRVS column that should be unique
7+
var SORT_BY = 'hostname'; // MRVS column to sort by
8+
9+
try {
10+
var raw = g_form.getValue(MRVS_NAME);
11+
var rows = raw ? JSON.parse(raw) : [];
12+
if (!Array.isArray(rows)) rows = [];
13+
14+
// Clear specified columns
15+
rows.forEach(function(row) {
16+
COLUMNS_TO_CLEAR.forEach(function(col) { if (row.hasOwnProperty(col)) row[col] = ''; });
17+
});
18+
19+
// Deduplicate by UNIQUE_KEY
20+
if (UNIQUE_KEY) {
21+
var seen = {};
22+
rows = rows.filter(function(row) {
23+
var key = String(row[UNIQUE_KEY] || '').toLowerCase();
24+
if (!key || seen[key]) return false;
25+
seen[key] = true;
26+
return true;
27+
});
28+
}
29+
30+
// Sort (case-insensitive)
31+
if (SORT_BY) {
32+
rows.sort(function(a, b) {
33+
var A = String(a[SORT_BY] || '').toLowerCase();
34+
var B = String(b[SORT_BY] || '').toLowerCase();
35+
if (A < B) return -1;
36+
if (A > B) return 1;
37+
return 0;
38+
});
39+
}
40+
41+
g_form.setValue(MRVS_NAME, JSON.stringify(rows));
42+
} catch (e) {
43+
console.error('MRVS normalise failed', e);
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading) return;
3+
4+
var MRVS_NAME = 'MY_MRVS';
5+
var COLUMNS_TO_CLEAR = ['env', 'region'];
6+
7+
var rows = [];
8+
try { rows = JSON.parse(g_form.getValue(MRVS_NAME) || '[]'); } catch (e) {}
9+
if (!Array.isArray(rows)) rows = [];
10+
11+
rows.forEach(function(row) {
12+
COLUMNS_TO_CLEAR.forEach(function(col) { if (row.hasOwnProperty(col)) row[col] = ''; });
13+
});
14+
15+
g_form.setValue(MRVS_NAME, JSON.stringify(rows));
16+
}
17+
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
var DynamicTableQueryUtil = Class.create();
2+
DynamicTableQueryUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {
3+
4+
getTableRow: function() {
5+
var tableName = this.getParameter('sysparm_table_name');
6+
var keyField = this.getParameter('sysparm_key_field');
7+
var keyValue = this.getParameter('sysparm_key_value');
8+
var fieldsParam = this.getParameter('sysparm_fields');
9+
var limitFields = !JSUtil.nil(fieldsParam);
10+
var desiredFields = limitFields ? fieldsParam.split(',') : [];
11+
12+
var result = {};
13+
var tableObj = {};
14+
var gr = new GlideRecord(tableName);
15+
16+
// Use addQuery for non-sys_id fields
17+
if (keyField === 'sys_id') {
18+
if (!gr.get(keyValue)) {
19+
return null;
20+
}
21+
} else {
22+
gr.addQuery(keyField, keyValue);
23+
gr.query();
24+
if (!gr.next()) {
25+
return null;
26+
}
27+
}
28+
29+
// Handle variables (if present)
30+
if (gr.variables) {
31+
for (var key in gr.variables) {
32+
if (!JSUtil.nil(gr.variables[key])) {
33+
var variableObj = gr.variables[key];
34+
tableObj['variables.' + key] = {
35+
fieldDisplayVal: variableObj.getDisplayValue() || String(variableObj),
36+
fieldVal: String(variableObj)
37+
};
38+
}
39+
}
40+
}
41+
42+
// Handle standard fields
43+
var fields = gr.getFields();
44+
for (var i = 0; i < fields.size(); i++) {
45+
var field = fields.get(i);
46+
var fieldName = field.getName();
47+
tableObj[fieldName] = {
48+
fieldDisplayVal: field.getDisplayValue() || String(field),
49+
fieldVal: String(field)
50+
};
51+
}
52+
53+
// Add sys_id explicitly
54+
tableObj['sys_id'] = {
55+
fieldDisplayVal: 'Sys ID',
56+
fieldVal: gr.getUniqueValue()
57+
};
58+
59+
// Filter fields if requested
60+
if (limitFields) {
61+
desiredFields.forEach(function(field) {
62+
field = field.trim();
63+
if (tableObj[field]) {
64+
result[field] = tableObj[field];
65+
}
66+
});
67+
} else {
68+
result = tableObj;
69+
}
70+
71+
return new JSON().encode(result);
72+
}
73+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
This solution provides a generic and reusable GlideAjax-based client-server interaction in ServiceNow that allows querying any table by passing:
2+
3+
Table name
4+
Key field and value
5+
Desired fields to retrieve
6+
7+
It dynamically returns field values from the server and populates them on the form, making it ideal for use cases like CMDB enrichment, entitlement lookups, or dynamic form population.
8+
9+
1. Client Script (onChange)
10+
Triggers on field change.
11+
Sends parameters to the Script Include via GlideAjax.
12+
Receives JSON response and sets target field value.
13+
14+
Parameters:
15+
sysparm_table_name: Table to query (e.g., sys_user)
16+
sysparm_key_field: Field to match (e.g., sys_id)
17+
sysparm_key_value: Value to match
18+
sysparm_fields: Comma-separated list of fields to retrieve
19+
20+
2. Script Include: DynamicTableQueryUtil
21+
22+
Processes incoming parameters.
23+
Queries the specified table and retrieves requested fields.
24+
Supports both standard fields and catalog item variables.
25+
Returns a JSON object with field values and display values.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading || newValue === '') {
3+
return;
4+
}
5+
6+
// Define parameters dynamically
7+
var tableName = 'sys_user'; // Change as needed
8+
var keyField = 'sys_id'; // Change as needed
9+
var fieldsToFetch = 'email'; // Comma-separated list
10+
var targetField = 'user'; // Field to populate
11+
12+
var ga = new GlideAjax('DynamicTableQueryUtil');
13+
ga.addParam('sysparm_name', 'getTableRow');
14+
ga.addParam('sysparm_table_name', tableName);
15+
ga.addParam('sysparm_key_field', keyField);
16+
ga.addParam('sysparm_key_value', newValue);
17+
ga.addParam('sysparm_fields', fieldsToFetch);
18+
ga.getXML(function(response) {
19+
var answer = response.responseXML.documentElement.getAttribute("answer");
20+
if (!answer) {
21+
alert('No response from Script Include');
22+
return;
23+
}
24+
25+
var parsedAnswer = JSON.parse(answer);
26+
if (parsedAnswer[fieldsToFetch]) {
27+
g_form.setValue(targetField, parsedAnswer[fieldsToFetch]['fieldVal']);
28+
} else {
29+
alert('error');
30+
}
31+
});
32+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
2+
if (isLoading || newValue === '') {
3+
return;
4+
}
5+
6+
// Define category-to-short description mapping
7+
var categoryToShortDescription = {
8+
'hardware': 'Hardware Issue - ',
9+
'software': 'Software Issue - ',
10+
'network': 'Network Issue - ',
11+
'inquiry': 'Inquiry/Help - ',
12+
'database': 'Database - '
13+
};
14+
15+
// Convert the selected value to lowercase for matching
16+
var selectedCategory = newValue.toLowerCase();
17+
18+
// If category exists in mapping, update the short description
19+
if (categoryToShortDescription.hasOwnProperty(selectedCategory)) {
20+
var existingDesc = g_form.getValue('short_description') || '';
21+
var prefix = categoryToShortDescription[selectedCategory];
22+
23+
// Only add prefix if it's not already there
24+
if (!existingDesc.startsWith(prefix)) {
25+
g_form.setValue('short_description', prefix + existingDesc);
26+
g_form.showFieldMsg('short_description', 'Short Description auto-updated based on category.', 'info');
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)