Week 8: GlideAjax: Calling the Server from the Client

This week closes the loop between Week 3's Client Scripts and Week 6's client-callable Script Includes: a real client/server round trip, triggered from the browser, running real server-side GlideRecord logic, with the result coming back into g_form. It's also the exact mental model Service Portal widgets build on starting in Week 12 — get comfortable with it here first.

Module 8 of 25 Week 8 of 26 ~3–4 Hours Hands-on Exercise Included

By the end of this week, you'll be able to

  • Call a client-callable Script Include from a Client Script using GlideAjax
  • Pass parameters to the server and parse a structured response back
  • Explain why this pattern is the direct ancestor of a widget's server call

1. The Standard Asynchronous GlideAjax Call

With IncidentAjax from Week 6 already client-callable, calling it from a Client Script follows one consistent shape: construct a GlideAjax instance naming the Script Include, name the method to call, and provide a callback for when the response arrives.

Client Script (onChange, assignment_group) — calling IncidentAjax
function onChange(control, oldValue, newValue, isLoading) {
  if (isLoading || newValue === '') return;

  var ga = new GlideAjax('IncidentAjax');
  ga.addParam('sysparm_name', 'getOpenCountForGroup');
  ga.addParam('sysparm_group', newValue);
  ga.getXML(handleResponse);
}

function handleResponse(response) {
  var count = response.responseXML.documentElement.getAttribute('answer');
  g_form.addInfoMessage('This group has ' + count + ' open incidents.');
}

sysparm_name is a reserved parameter naming the method to invoke on the Script Include; every other addParam() call is a value that method reads via this.getParameter(name) on the server. The whole round trip is asynchronous — handleResponse runs whenever the server actually replies, not immediately after getXML() returns.

2. Passing Parameters & Returning Structured Data

A Script Include method invoked via GlideAjax returns its value as the answer attribute of an XML response by default. For anything richer than a single string or number, return a JSON string and parse it client-side:

Script Include method — returning structured data
getGroupSummary: function() {
  var groupSysId = this.getParameter('sysparm_group');
  var utils = new IncidentUtils();

  var summary = {
    openCount: utils.countOpenByGroup(groupSysId),
    overdueCount: utils.countOverdueByGroup(groupSysId)
  };

  return JSON.stringify(summary);
}
Client Script — parsing the JSON response
function handleResponse(response) {
  var raw = response.responseXML.documentElement.getAttribute('answer');
  var summary = JSON.parse(raw);
  g_form.addInfoMessage(summary.openCount + ' open, ' + summary.overdueCount + ' overdue.');
}

3. Synchronous Calls — and Why to Avoid Them

getXMLWait() exists as a synchronous variant that blocks until the response arrives, but it freezes the browser tab while waiting and is discouraged in current ServiceNow guidance — the callback-based getXML() pattern above is the one to default to for anything new you write.

4. Preview: This Is a Widget's Server Call, Minus the Wrapper

Hold onto this exact mental model — construct a request, send parameters, get a response back asynchronously, update the UI in a callback — because starting in Week 12, c.server.update() inside a Service Portal widget does precisely this same round trip. The widget framework just removes the manual GlideAjax/Script Include ceremony and gives every widget's own server script the role IncidentAjax played here.

5. Hands-on Exercise

Hands-on

Wire up the group-summary lookup end to end

Requirements:

  1. Extend IncidentUtils from Week 6 with countOverdueByGroup(groupSysId), reusing your isOverdue() logic per record.
  2. Add getGroupSummary() to IncidentAjax as shown above.
  3. Write the onChange Client Script on assignment_group, calling getGroupSummary and displaying both counts via g_form.addInfoMessage().
  4. Test by changing the assignment group on an incident form and confirming the message updates with real numbers from your instance's data.
Hint

If handleResponse never fires, check the browser console first, then confirm the Script Include's "Client callable" checkbox is actually checked — a non-callable Script Include fails the GlideAjax request silently in a way that's easy to miss without opening dev tools.

6. Knowledge Check

Four quick questions. Expand each to check your answer.

Q1

What does the sysparm_name parameter in a GlideAjax call actually control?

It names the specific method on the target client-callable Script Include that should be invoked — GlideAjax always calls into one Script Include, and sysparm_name is how it selects which method on that Script Include to run for this particular request.

Q2

Why is a callback-based getXML() call generally preferred over the synchronous getXMLWait()?

getXMLWait() blocks the browser tab until the server responds, freezing the UI for however long that round trip takes. getXML() with a callback lets the browser stay responsive while waiting and is the pattern current ServiceNow guidance recommends by default.

Q3

How do you return something richer than a single string or number from a GlideAjax-called method?

Build a plain JavaScript object or array on the server, serialize it with JSON.stringify(), and return that string as the method's result. The client-side callback then reads it off the answer attribute and parses it back into an object with JSON.parse().

Q4

How does GlideAjax relate to how a Service Portal widget calls its server script?

They're the same underlying pattern: construct a request, send parameters to the server, receive a response asynchronously, and update the UI in a callback. A widget's c.server.update() (covered starting Week 12) does this same round trip, just with the manual GlideAjax/Script Include wiring replaced by the widget framework's built-in server-script mechanism.