logo

NJP

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!

View original source

https://www.servicenow.com/community/developer-advocate-blog/understanding-the-data-input-object-in-service-portal-widgets/ba-p/3173684