Understanding the data/input object in Service Portal widgets
New article articles in ServiceNow Community
·
Feb 10, 2025
·
article
I feel like I get to teach this ServiceNow concept at least once a month and so it’s about time that I write it all out!
Hi everyone, I’m Earl, one of your developer advocates here at ServiceNow, and today we’ll explore the dance between the **server script** and the **client script**, and how the `data` and `input` objects enable our widgets to communicate back and forth.
Basically, if you’ve ever worked with ServiceNow widgets and found yourself wondering, “Wait, how does `data` actually get from point A to point B?” then this is for you.
## **The Cheat Sheet**
Maybe you’re here just for the cheat sheet/summary. Here you go:
## **The Big Picture**
Before we jump into code, let’s take a moment to paint the bigger picture. In a ServiceNow Service Portal widget, we have two main pieces:
1. **Server Script** – This runs on the ServiceNow server. It initializes or updates the `data` object.
2. **Client Script** – This runs in the user’s browser. It sees `$scope.data` and can interact with the user, update things on the screen, and—crucially—send information back to the server using `$scope.server.update()`.
At first, it might sound a bit like a tennis match: the ball (our data) goes from server to client, then from client to server, and back again. But once you see it in action, it feels quite intuitive.
## **A Minimal Example**
### **Server Script**
```js
(function() {
data.serverMessage = "Hello from the server!";
})();
```
### **Client Controller**
```js
api.controller=function() {
var c = this;
console.log("Server says:", c.data.serverMessage);
}
```
### **HTML Template**
```html
The server message is: {{data.serverMessage}}
```
Here’s our first mini-walkthrough. You can think of it as the “Hello World” of ServiceNow widgets.
* In our **Server Script**, we’re setting `data.serverMessage = "Hello from the server!"`.
* The **Client Controller** sees `c.data.serverMessage` as soon as the page loads.
* Our **HTML template** simply displays it with `{{data.serverMessage}}`.
Your data is officially traveling across the internet from your instance to the user’s browser. It’s a small start, but it’s the foundation of everything else we’ll be exploring.
## **Introducing** `input`
``
```js
/* Server Script */
(function() {
if (input && input.displayName) {
data.displayName = input.displayName;
} else {
data.displayName = "No name provided";
}
})();
```
Now let’s add a twist: the **input** object. Sometimes, your widget needs parameters—maybe the user wants to provide some information. In Service Portal, that’s where `input` comes into play.
Think of `input` as the “stuff coming in” from the client script. If `input.displayName` exists (from the client script/user), we set `data.displayName` to that; otherwise, we default it to “No name provided.”
This ensures your widget can be adapted to different situations without needing to rewrite the code every time.
## **Client-to-Server Communication**
So far, we’ve learned that the server sends data to the client on page load. But what if we want to go the other way? Let’s create a user-driven scenario:
1. The user types a greeting in an input box.
2. We send that greeting to the server script.
3. The server script modifies some data based on the user’s input.
4. The server sends a response back.
.png")
## **Code for Two-Way Data Exchange**
### **Server Script**
```js
(function() {
data.serverMessage = "Hello from the server!";
if (input && input.greet && input.greetText) {
data.serverMessage = "Server responds: " + input.greetText;
}
if (input && input.displayName) {
data.displayName = input.displayName;
} else {
data.displayName = "No name provided";
}
})();
```
### **Client Controller**
```js
api.controller=function() {
var c = this;
c.clientText = "";
c.sayHello = function() {
c.data.greet = true;
c.data.greetText = c.clientText;
c.server.update().then(function() {
alert("Server says: " + c.data.serverMessage);
});
};
}
```
### **HTML Template**
```html
Hello World Widget
Display Name: {{data.displayName}}
Send Greeting
Server Message: {{data.serverMessage}}
```
Here’s where the **magic** happens:
1. **Server Script** sets a default `serverMessage` and updates it if we see `input.greetText`.
2. **Client Script** collects the user’s input in `c.clientText` and uses `c.server.update()` to send data back.
3. ServiceNow receives this data as `input.greetText`, updates `data.serverMessage`, and returns it to the client.
4. The client’s `c.data` is refreshed, so we can display the new `serverMessage`.
This pattern is crucial for any widget that needs to respond dynamically to user actions. You can query tables, run server-side logic, and funnel the results back to the user, all in a matter of milliseconds.
## **Recap of the Data Flow**
Let’s recap the journey of our data:
1. **Page Load**
* The **server script** runs, initializing the `data` object.
* This `data` object travels to the browser as `c.data`.
2. **Client Updates**
* The user interacts with the widget (e.g., types in a text box).
* The client sets `c.data` properties and calls `c.server.update()`.
3. **Server Re-run**
* The server script runs again, reading what the client sent via `input.*`.
* The script updates the `data` object based on that new input.
4. **Data Returns**
* The updated `data` object is sent back to the browser, refreshing `c.data`.
.png")
## **Real example**
### **Server Script**
```js
(function() {
var incidentGr = new GlideRecord('task');
if (input && input.textQuery){
data.textQuery = input.textQuery || 'no query provided';
incidentGr.addEncodedQuery('short_descriptionLIKE' + input.textQuery);
}
incidentGr.setLimit(10);
incidentGr.query();
data.tasks = [];
while(incidentGr.next()){
var task = {
number: incidentGr.getValue('number'),
short_description: incidentGr.getValue('short_description')
}
data.tasks.push(task);
}
})();
```
### **Client Controller**
```js
api.controller=function() {
var c = this;
c.clientText = "";
c.searchForText = function() {
c.data.textQuery = c.clientText;
c.server.update().then(function() {
console.log(c.data.tasks)
});
};
}
```
### **HTML Template**
```html
List of tasks
Text query: {{data.textQuery}}
Query
-
{{task.number}} - {{task.short_description}}
```
## **Putting It into Practice**
Next time you’re building a widget:
1. Start simple: set default data in your server script and confirm you can display it in the template.
2. Introduce user input: accept some text or a choice in the client script.
3. Communicate: use `c.server.update()` to send data back, and have the server script respond accordingly.
## **Final Thoughts**
You’ve just learned how the `data` object is formed on the **server**, delivered to the **client**, and then travels back again via `input` on updates. In the real example, you can see the common use-case of taking a user’s input (text, clicks, etc.) and affect the server script of the widget itself.
That’s all for today. For most of us Service Portal veterans, this data/input interaction is second nature to use at this point and hopefully that’s you now too!
https://www.servicenow.com/community/developer-advocate-blog/understanding-the-data-input-object-in-service-portal-widgets/ba-p/3173684
Earl Duque