Skip to content

Commit fced621

Browse files
committed
Merge branch 'add-context-aware-va-topics' of https://github.com/ChaseMillers/code-snippets into add-context-aware-va-topics
2 parents 8bbb91e + 077e4f5 commit fced621

194 files changed

Lines changed: 7510 additions & 101 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
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)