Check a page for accessibility
Review supplied markup or descriptions for practical accessibility issues and fixes.
5,037,546 AI resources indexedWorking toward the world’s largest AI resource index.
Build Service Portal widgets (sp_widget) with synchronized server/client/HTML — data.* initialization, ng-click + controller method matching, c.server.get action handlers, and Angular directive usage.
---
name: widget-coherence-b461dd9996fc
description: Build Service Portal widgets (sp_widget) with synchronized server/client/HTML — data.* initialization, ng-click + controller method matching, c.server.get action handlers, and Angular directive usage.
version: 1.0.0
tools:
- snow_artifact_manage (action='create')
- snow_artifact_manage (action='update')
- snow_validate_widget_coherence
- snow_widget_test
- snow_artifact_manage (action='find')
---
# Widget Coherence for ServiceNow Service Portal
Service Portal widgets MUST have perfect communication between Server Script, Client Controller, and HTML Template. This is not optional - widgets fail when these components don't talk to each other correctly.
## The Three-Way Contract
Every widget requires synchronized communication:
### 1. Server Script Must:
- Initialize ALL `data.*` properties that HTML will reference
- Handle EVERY `input.action` that client sends via `c.server.get()`
- Return data in the format the client expects
### 2. Client Controller Must:
- Implement EVERY method called by `ng-click` in HTML
- Use `c.server.get({action: 'name'})` for server communication
- Update `c.data` when server responds
### 3. HTML Template Must:
- Only reference `data.*` properties that server provides
- Only call methods defined in client controller
- Use correct Angular directives and bindings
## Data Flow Patterns
### Server → Client → HTML
```javascript
// SERVER SCRIPT
;(function () {
data.incidents = []
data.loading = true
var gr = new GlideRecord("incident")
gr.addQuery("active", true)
gr.setLimit(10)
gr.query()
while (gr.next()) {
data.incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
})
}
data.loading = false
})()
```
```javascript
// CLIENT CONTROLLER
api.controller = function ($scope) {
var c = this
c.selectIncident = function (incident) {
c.selectedIncident = incident
}
}
```
```html
<!-- HTML TEMPLATE -->
<div ng-if="data.loading">Loading...</div>
<div ng-if="!data.loading">
<div ng-repeat="incident in data.incidents" ng-click="c.selectIncident(incident)">
{{incident.number}}: {{incident.short_description}}
</div>
</div>
```
### Client → Server (Actions)
```javascript
// CLIENT CONTROLLER
c.saveIncident = function () {
c.server
.get({
action: "save_incident",
incident_data: c.formData,
})
.then(function (response) {
if (response.data.success) {
c.data.message = "Saved successfully"
}
})
}
```
```javascript
// SERVER SCRIPT
if (input && input.action === "save_incident") {
var gr = new GlideRecord("incident")
gr.initialize()
gr.setValue("short_description", input.incident_data.short_description)
data.new_sys_id = gr.insert()
data.success = !!data.new_sys_id
}
```
## Validation Checklist
Before deploying a widget, verify:
- [ ] Every `data.property` in server is used in HTML or client
- [ ] Every `ng-click="c.method()"` has matching `c.method` in client
- [ ] Every `c.server.get({action: 'x'})` has matching `if(input.action === 'x')` in server
- [ ] No orphaned methods or unused data properties
- [ ] All `data.*` properties are initialized in server (even if empty)
## Common Failures
### Action Name Mismatch
```javascript
// CLIENT - sends 'saveIncident'
c.server.get({ action: "saveIncident" })
// SERVER - expects 'save_incident' (MISMATCH!)
if (input.action === "save_incident") {
}
```
### Method Name Mismatch
```html
<!-- HTML - calls saveData() -->
<button ng-click="c.saveData()">Save</button>
```
```javascript
// CLIENT - defines save() (MISMATCH!)
c.save = function () {}
```
### Undefined Data Properties
```html
<!-- HTML - references user.email -->
<span>{{data.user.email}}</span>
```
```javascript
// SERVER - only sets user.name (user.email is undefined!)
data.user = { name: userName }
```
## Angular Directives Reference
| Directive | Purpose |
| ------------------- | ---------------------------------------- |
| `ng-if` | Conditionally render element |
| `ng-show`/`ng-hide` | Toggle visibility (element stays in DOM) |
| `ng-repeat` | Iterate over array |
| `ng-click` | Handle click events |
| `ng-model` | Two-way data binding |
| `ng-class` | Dynamic CSS classes |
| `ng-disabled` | Disable form elements |
---
name: widget-coherence-b461dd9996fc
description: Build Service Portal widgets (sp_widget) with synchronized server/client/HTML — data.* initialization, ng-click + controller method matching, c.server.get action handlers, and Angular directive usage.
version: 1.0.0
tools:
- snow_artifact_manage (action='create')
- snow_artifact_manage (action='update')
- snow_validate_widget_coherence
- snow_widget_test
- snow_artifact_manage (action='find')
---
# Widget Coherence for ServiceNow Service Portal
Service Portal widgets MUST have perfect communication between Server Script, Client Controller, and HTML Template. This is not optional - widgets fail when these components don't talk to each other correctly.
## The Three-Way Contract
Every widget requires synchronized communication:
### 1. Server Script Must:
- Initialize ALL `data.*` properties that HTML will reference
- Handle EVERY `input.action` that client sends via `c.server.get()`
- Return data in the format the client expects
### 2. Client Controller Must:
- Implement EVERY method called by `ng-click` in HTML
- Use `c.server.get({action: 'name'})` for server communication
- Update `c.data` when server responds
### 3. HTML Template Must:
- Only reference `data.*` properties that server provides
- Only call methods defined in client controller
- Use correct Angular directives and bindings
## Data Flow Patterns
### Server → Client → HTML
```javascript
// SERVER SCRIPT
;(function () {
data.incidents = []
data.loading = true
var gr = new GlideRecord("incident")
gr.addQuery("active", true)
gr.setLimit(10)
gr.query()
while (gr.next()) {
data.incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
})
}
data.loading = false
})()
```
```javascript
// CLIENT CONTROLLER
api.controller = function ($scope) {
var c = this
c.selectIncident = function (incident) {
c.selectedIncident = incident
}
}
```
```html
<!-- HTML TEMPLATE -->
<div ng-if="data.loading">Loading...</div>
<div ng-if="!data.loading">
<div ng-repeat="incident in data.incidents" ng-click="c.selectIncident(incident)">
{{incident.number}}: {{incident.short_description}}
</div>
</div>
```
### Client → Server (Actions)
```javascript
// CLIENT CONTROLLER
c.saveIncident = function () {
c.server
.get({
action: "save_incident",
incident_data: c.formData,
})
.then(function (response) {
if (response.data.success) {
c.data.message = "Saved successfully"
}
})
}
```
```javascript
// SERVER SCRIPT
if (input && input.action === "save_incident") {
var gr = new GlideRecord("incident")
gr.initialize()
gr.setValue("short_description", input.incident_data.short_description)
data.new_sys_id = gr.insert()
data.success = !!data.new_sys_id
}
```
## Validation Checklist
Before deploying a widget, verify:
- [ ] Every `data.property` in server is used in HTML or client
- [ ] Every `ng-click="c.method()"` has matching `c.method` in client
- [ ] Every `c.server.get({action: 'x'})` has matching `if(input.action === 'x')` in server
- [ ] No orphaned methods or unused data properties
- [ ] All `data.*` properties are initialized in server (even if empty)
## Common Failures
### Action Name Mismatch
```javascript
// CLIENT - sends 'saveIncident'
c.server.get({ action: "saveIncident" })
// SERVER - expects 'save_incident' (MISMATCH!)
if (input.action === "save_incident") {
}
```
### Method Name Mismatch
```html
<!-- HTML - calls saveData() -->
<button ng-click="c.saveData()">Save</button>
```
```javascript
// CLIENT - defines save() (MISMATCH!)
c.save = function () {}
```
### Undefined Data Properties
```html
<!-- HTML - references user.email -->
<span>{{data.user.email}}</span>
```
```javascript
// SERVER - only sets user.name (user.email is undefined!)
data.user = { name: userName }
```
## Angular Directives Reference
| Directive | Purpose |
| ------------------- | ---------------------------------------- |
| `ng-if` | Conditionally render element |
| `ng-show`/`ng-hide` | Toggle visibility (element stays in DOM) |
| `ng-repeat` | Iterate over array |
| `ng-click` | Handle click events |
| `ng-model` | Two-way data binding |
| `ng-class` | Dynamic CSS classes |
| `ng-disabled` | Disable form elements |
Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.