UI Builder / Asset Management Workspace – How to capture changed fields when using the existing Save

girishbs06
Tera Expert

Hi Community,

I’m working on an Asset Management Workspace / Asset Workspace in ServiceNow and need guidance on handling field changes when the user saves a Hardware Asset record.

Requirement

I have a Hardware Asset (alm_hardware) record opened from a Typeahead search in UI Builder.

The flow is:

Typeahead Asset Tag search → select asset → /record route → Hardware Asset form

The standard Workspace form has the existing Save button.

When a user changes one or more fields, I need the following behavior:

User opens an existing alm_hardware record.

User modifies one or more fields.

The modified values should remain visible in the form.

User clicks the existing Save button.

The record should be saved normally.

After the successful save, I want to display a notification/alert showing which fields were changed, ideally something like:

State: In Use → In Stock

Location: Bangalore → Mumbai

Assigned to: User A → User B

Important requirements

I do not want to create a second Save button.

I want to use the existing Workspace Save action.

I don't want to replace the standard editable form.

The customization should apply only to Asset Management Workspace, not globally to the classic UI or other workspaces.

I need to preserve the normal Save behavior.

What I have investigated

The form is using a Form Controller for alm_hardware.

The Form Controller JSON contains an actionConfigId, and the form's action bar is enabled, so the standard Save button is visible.

I checked UX Form Actions and found generic Save actions, but I don't want to modify the generic Save action because it could affect other tables/workspaces.

I also checked UX Form Action Layouts filtered for alm_hardware, but there is no Hardware-specific Save layout.

I also noticed the Form Controller has events such as:

[Form] Form status changed

[Notification] Add notification requested

My question

What is the recommended ServiceNow-supported approach in UI Builder / Configurable Workspace to:

detect the fields changed in the Workspace form → allow the existing Save action to save normally → after successful save, identify the changed fields/old and new values → display a notification?

Specifically, can this be achieved using:

Form Controller events/status?

A Workspace Client Script?

Declarative Action / UXF Client Action?

An Add-on Event Mapping?

The existing Save action's client script?

Another supported UI Builder mechanism?

I would also appreciate an example of the correct script/API for obtaining the changed fields and their old/new values in a Workspace form.

Thanks!

5 REPLIES 5

I couldn't validate on my side that the form controller for the event [Field] Field value changed would actually print the old value, at least for me it does no, only the new one, see below: 

event = {
  "elementId": "record",
  "name": "CTRL_RECORD#FIELD_VALUE_CHANGED",
  "payload": {
    "displayValue": "Z",
    "fieldName": "last_name",
    "value": "Z"
  },


But either way, your comment helped me with other idea, which seems to achieve what @girishbs06 wanted, see below :

There is a property at the level of the form controller called unsavedChanges, we can make the use of this to provide the old and new value with just 1 event mapping, this property is updated each time a value changes on the form, and cleared once the form is submitted. 

1 - Go to the form controller and find the event [Form] Form submit completed, and add the "Add alert notifications" event.

DiogoRamos_3-1790933157537.png


2 - Click the Add alert notifications event and set the  "Script" option on add alert notification on top right 

DiogoRamos_1-1790932381312.png

3 - Copy the following code 

/**
* @param {params} params
* @param {api} params.api
* @param {any} params.event
*/
function evaluateEvent({ api, event }) {
    const raw = api.data.record.unsavedChanges;
    let parsed = [];

    try {
        // Upon testing I validated this comes as a string : We have to convert to an array
        parsed = typeof raw === 'string' ? JSON.parse(raw) : (Array.isArray(raw) ? raw : []);
    } catch (e) {
        parsed = [];
    }

    if (parsed.length === 0) {
        return {
            items: [{
                icon: "circle-info-outline",
                content: "No changes detected",
                header: "",
                status: "positive",
                action: { type: "dismiss" }
            }]
        };
    }

    const items = parsed.map(item => {
        const label = item.label || item.name || 'Unknown';
        const oldVal = item.originalDisplayValue || 'N/A';
        const newVal = item.displayValue || 'N/A';
        
        return {
            icon: "circle-info-outline",
            content: `${label}: ${oldVal} → ${newVal}`,
            header: "",
            status: "positive",
            action: { type: "dismiss" }
        };
    });

    return { items: items };
}

4 - Result : 

DiogoRamos_2-1790932919794.png


I hope this helps !