Skip to content

Commit 05e1a0e

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into feature/auto-incident-from-case-email
2 parents b3aaedf + e5fad12 commit 05e1a0e

File tree

110 files changed

+4764
-71
lines changed

Some content is hidden

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

110 files changed

+4764
-71
lines changed
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+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Auto-Populate Short Description (Client Script)
2+
## Overview
3+
4+
This client script automatically updates the Short Description field in ServiceNow whenever a user selects a category on the form. It improves data consistency, saves time, and ensures that short descriptions remain meaningful and standardized.
5+
6+
## How It Works
7+
8+
When a user selects a category such as Hardware, Software, or Network, the script automatically prefixes the existing short description with a corresponding label (for example, “Hardware Issue –”).
9+
This makes incident records easier to identify and improves the quality of data entry.
10+
11+
## Configuration Steps
12+
13+
1. Log in to your ServiceNow instance with admin or developer access.
14+
2. Navigate to System Definition → Client Scripts.
15+
3. Create a new Client Script with the following details:
16+
17+
```
18+
Table: Incident
19+
Type: onChange
20+
Field name: category
21+
Copy and paste the provided script into the Script field.
22+
Save the record and make sure the script is active.
23+
```
24+
25+
## Testing
26+
27+
1. Open any existing or new Incident record.
28+
2. Select a category such as Hardware or Software.
29+
3. The Short Description field will automatically update with the corresponding prefix.
30+
31+
## Benefits
32+
33+
Speeds up data entry for users.
34+
Maintains consistency in short descriptions.
35+
Reduces manual effort and human errors.
36+
Enhances clarity in incident listings and reports.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Dynamic script to make fields read only
2+
3+
It runs when the field value changes.On change client script
4+
If the new value equals '7', it retrieves all editable fields using g_form.getEditableFields().
5+
Then it loops through each field and sets it to read-only using g_form.setReadOnly().
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
It runs when the field value changes.
3+
If the new value equals '7', it retrieves all editable fields using g_form.getEditableFields().
4+
Then it loops through each field and sets it to read-only using g_form.setReadOnly().
5+
6+
*/
7+
8+
9+
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
10+
if (isLoading || newValue === '') {
11+
return;
12+
}
13+
14+
15+
if (newValue == '7') { // update condition as required
16+
var fields = g_form.getEditableFields();
17+
for (var i = 0; i < fields.length; i++) {
18+
g_form.setReadOnly(fields[i].getName(), true);
19+
}
20+

0 commit comments

Comments
 (0)