client-scripts

安装量: 50
排名: #14948

安装

npx skills add https://github.com/groeimetai/snow-flow --skill client-scripts

Client Script Patterns for ServiceNow

Client Scripts run in the user's browser and control form behavior. Unlike server-side scripts, client scripts can use modern JavaScript (ES6+) in modern browsers.

Client Script Types Type When it Runs Use Case onLoad Form loads Set defaults, hide/show fields, initial setup onChange Field value changes React to user input, cascading updates onSubmit Form submitted Validation before save onCellEdit List cell edited Validate inline edits The g_form API Getting and Setting Values // Get field value var priority = g_form.getValue('priority'); var callerName = g_form.getDisplayValue('caller_id'); // Reference display value

// Set field value g_form.setValue('priority', '1'); g_form.setValue('assigned_to', userSysId, 'John Smith'); // Reference with display

// Clear a field g_form.clearValue('assignment_group');

Field Visibility and State // Show/Hide fields g_form.setVisible('u_internal_notes', false); g_form.setDisplay('u_internal_notes', false); // Removes from DOM

// Make field mandatory g_form.setMandatory('short_description', true);

// Make field read-only g_form.setReadOnly('caller_id', true);

// Disable field (grayed out but visible) g_form.setDisabled('state', true);

Messages and Validation // Field-level messages g_form.showFieldMsg('email', 'Invalid email format', 'error'); g_form.hideFieldMsg('email');

// Form-level messages g_form.addInfoMessage('Record saved successfully'); g_form.addErrorMessage('Please fix the errors below'); g_form.clearMessages();

// Flash a field to draw attention g_form.flash('priority', '#ff0000', 0); // Red flash

Sections and Labels // Collapse/Expand sections g_form.setSectionDisplay('notes', false); // Collapse g_form.setSectionDisplay('notes', true); // Expand

// Change field label g_form.setLabelOf('short_description', 'Issue Summary');

Common Patterns Pattern 1: onLoad - Set Defaults function onLoad() { // Only on new records if (g_form.isNewRecord()) { // Set default priority g_form.setValue('priority', '3');

// Set caller to current user
g_form.setValue('caller_id', g_user.userID);

// Hide internal fields from end users
if (!g_user.hasRole('itil')) {
  g_form.setVisible('assignment_group', false);
  g_form.setVisible('assigned_to', false);
}

} }

Pattern 2: onChange - Cascading Updates function onChange(control, oldValue, newValue, isLoading) { // Don't run during form load if (isLoading) return;

// When category changes, clear subcategory if (newValue != oldValue) { g_form.setValue('subcategory', ''); g_form.clearValue('u_item'); }

// Auto-set priority based on category if (newValue == 'security') { g_form.setValue('priority', '1'); g_form.setReadOnly('priority', true); } else { g_form.setReadOnly('priority', false); } }

Pattern 3: onChange with GlideAjax function onChange(control, oldValue, newValue, isLoading) { if (isLoading || newValue == '') return;

// Get data from server var ga = new GlideAjax('MyScriptInclude'); ga.addParam('sysparm_name', 'getUserDetails'); ga.addParam('sysparm_user_id', newValue); ga.getXMLAnswer(function(response) { var data = JSON.parse(response);

// Update form with server data
g_form.setValue('location', data.location);
g_form.setValue('department', data.department);
g_form.setValue('u_vip', data.vip);

if (data.vip == 'true') {
  g_form.setValue('priority', '1');
  g_form.flash('priority', '#ffff00', 2);
}

}); }

Pattern 4: onSubmit - Validation function onSubmit() { // Validate email format var email = g_form.getValue('u_email'); if (email && !isValidEmail(email)) { g_form.showFieldMsg('u_email', 'Please enter a valid email', 'error'); return false; // Prevent submit }

// Require close notes when resolving var state = g_form.getValue('state'); var closeNotes = g_form.getValue('close_notes'); if (state == '6' && !closeNotes) { g_form.showFieldMsg('close_notes', 'Close notes required', 'error'); g_form.setMandatory('close_notes', true); return false; }

// Confirm before high-priority submission var priority = g_form.getValue('priority'); if (priority == '1') { return confirm('This will create a Priority 1 incident. Continue?'); }

return true; // Allow submit }

function isValidEmail(email) { var regex = /^[^\s@]+@[^\s@]+.[^\s@]+$/; return regex.test(email); }

Pattern 5: Conditional Mandatory Fields function onChange(control, oldValue, newValue, isLoading) { if (isLoading) return;

// Category "Hardware" requires asset tag var isHardware = newValue == 'hardware'; g_form.setMandatory('u_asset_tag', isHardware); g_form.setDisplay('u_asset_tag', isHardware);

// Category "Software" requires application name var isSoftware = newValue == 'software'; g_form.setMandatory('u_application', isSoftware); g_form.setDisplay('u_application', isSoftware); }

GlideAjax Pattern (Server Communication) Client Script function onChange(control, oldValue, newValue, isLoading) { if (isLoading || !newValue) return;

var ga = new GlideAjax('IncidentUtils'); ga.addParam('sysparm_name', 'getRelatedIncidents'); ga.addParam('sysparm_ci', newValue); ga.getXMLAnswer(handleResponse); }

function handleResponse(response) { var result = JSON.parse(response);

if (result.count > 0) { g_form.addWarningMessage('There are ' + result.count + ' related open incidents for this CI'); } }

Server Script Include var IncidentUtils = Class.create(); IncidentUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {

getRelatedIncidents: function() { var ci = this.getParameter('sysparm_ci'); var result = { count: 0, incidents: [] };

var gr = new GlideRecord('incident');
gr.addQuery('cmdb_ci', ci);
gr.addQuery('active', true);
gr.query();

result.count = gr.getRowCount();
while (gr.next()) {
  result.incidents.push({
    number: gr.getValue('number'),
    short_description: gr.getValue('short_description')
  });
}

return JSON.stringify(result);

},

type: 'IncidentUtils' });

g_user Object // Current user information var userName = g_user.userName; // User name var userID = g_user.userID; // sys_id var firstName = g_user.firstName; // First name var lastName = g_user.lastName; // Last name var fullName = g_user.getFullName(); // Full name

// Role checks if (g_user.hasRole('admin')) { } if (g_user.hasRole('itil')) { } if (g_user.hasRoleExactly('incident_manager')) { } // Exact match, no admin override

// Multiple roles if (g_user.hasRoleFromList('itil,incident_manager')) { }

Performance Best Practices 1. Minimize Server Calls // ❌ BAD - Multiple GlideAjax calls onChange: getUserLocation(); onChange: getUserDepartment(); onChange: getUserManager();

// ✅ GOOD - Single call returning all data onChange: getUserDetails(); // Returns location, department, manager

  1. Use isLoading Parameter function onChange(control, oldValue, newValue, isLoading) { // ❌ BAD - Runs during form load callServer(newValue);

// ✅ GOOD - Skip during load if (isLoading) return; callServer(newValue); }

  1. Debounce Rapid Changes var timeout; function onChange(control, oldValue, newValue, isLoading) { if (isLoading) return;

clearTimeout(timeout); timeout = setTimeout(function() { performExpensiveOperation(newValue); }, 300); // Wait 300ms for typing to stop }

Common Mistakes Mistake Problem Solution Forgetting isLoading check Script runs unnecessarily on load Always check if (isLoading) return; Blocking onSubmit UI freezes on slow validation Use async validation with callback No error handling in GlideAjax Silent failures Add error callbacks Testing only in one browser Cross-browser issues Test Chrome, Firefox, Edge Direct DOM manipulation Breaks with UI updates Use g_form API

返回排行榜