Updating records from a repeater

Luca Armienti1
Tera Expert

Hi,

 

I have a repeater that looks somewhat like a survey:

fe_checklist.png

 

UI_builder.png

 

 

The repeater is created with a look-up record data resource.

 

Every item created by the repeater has some input fields, and every item is basically a record in the ServiceNow database. I have to update the records based on the input inserted inside every item when the user click on the save button.

 

My issue is that trying to use Data.look_up_record.results inside a client script, or item.value inside every item, i get the initial value that i got from the lookup, not dynamic; without the input inserted by the user. 

The default way to update data with the UIBuilder is to save the input field Payload.value into client state parameters, and then use the client states for the "update record" operations, but here i have a dynamic number of fields because of the repeater, so i can't do that, i can't create client states for every field i create.

 

So how am I supposed to updating data from a repeater? i tried to find a solution both putting the save button in every item (not optimal) or for all the page, without success.

 

Thanks,

Luca

 

 

2 ACCEPTED SOLUTIONS

Arnoud Kooi
ServiceNow Employee
ServiceNow Employee

As a test, I created below client script.

This can be triggered by any change event of your elements.

 

 

function handler({api, event, helpers, imports}) {

    let elementId = event.elementId;
    let sysId = event.context.item.value._row_data.uniqueValue;
    let value = event.payload.value;

    let updatedData = JSON.parse(JSON.stringify(api.state.updatedData));
    
    let element = updatedData[sysId] || {};
    element[elementId] = value;
    updatedData[sysId] = element;
    api.setState("updatedData", updatedData);
    console.log(updatedData);
    
}

 

 

If you give your elements an id of your field names you could iterate over the object and update the data...

In my test UIB page I have a list of incidents with two elements:

ArnoudKooi_0-1682501259805.png

On every update the client state parameter gets build up:

 

{
    "4045362fdbcb8910f0ff4e68139619a4": {
        "short_description": "RANDOM TESTDATA ",
        "active": true
    },
    "1eaecf121beb3410ba6a437cbc4bcb28": {
        "short_description": "new value"
    }
}

 

When you implement a save button, you can iterate over that object. on update your records

View solution in original post

What i did is:


1) Create an page level event handler on the body, "update_answer", with three properties: fieldName (instead of elementID), itemId(the sysId of the record), value.

customevent1.png

 

 

 

2) Call this event everytime someone select/change value in an input field, and pass the three properties above. 

customevent2.png

customevent2.3.png

 

3) Update the client state parameter with the event handler on the body with a script very similar to yours.

 

let elementId = event.payload.fieldName;
let sysId = event.payload.sysId;
let value = event.payload.value;

let updatedData = JSON.parse(JSON.stringify(api.state.updatedData));

let element = updatedData[sysId] || {};
element[elementId] = value;
updatedData[sysId] = element;
//api.setState("updatedData", updatedData);
console.log(updatedData);
    return {
        propName: 'updatedData',
        value: updatedData
    };

 

customevent3.png

 

4) execute the record update with the event handler on the save button and using the updated client state parameter.

 

I feel better doing it (because of my past experience on other frontend framework) but also: 

event.context.item.value._row_data.uniqueValue;

 

Was not working for me, I couldn't access item.value from context in the component using scripts, while for some reason I can access item with the form.

 

View solution in original post

7 REPLIES 7

JagjeetSingh
Kilo Sage

Hi,

 

You can use JSON Type of state parameter to store the values. With every event inside the repeater you get the index of the item inside repeater. Use that inside the client script and save the value in JSON parameter for that index.

 

Lastly, you can use that JSON to save the response.

Jagjeet Singh
ServiceNow Community Rising Star 2022/2023

Hi,

 

First thanks for you answer.

 

So what you are saying is to:

 

1) Create a JSON client state and initialize it with data.look_up_record, so that it has the same structure as the repeater.

2) Create an event handler inside every input field to change that client state (with setState?) depending on the payload.value.

3) use the updated JSON client state when clicking on the "save" button.

 

Am I correct?

Arnoud Kooi
ServiceNow Employee
ServiceNow Employee

As a test, I created below client script.

This can be triggered by any change event of your elements.

 

 

function handler({api, event, helpers, imports}) {

    let elementId = event.elementId;
    let sysId = event.context.item.value._row_data.uniqueValue;
    let value = event.payload.value;

    let updatedData = JSON.parse(JSON.stringify(api.state.updatedData));
    
    let element = updatedData[sysId] || {};
    element[elementId] = value;
    updatedData[sysId] = element;
    api.setState("updatedData", updatedData);
    console.log(updatedData);
    
}

 

 

If you give your elements an id of your field names you could iterate over the object and update the data...

In my test UIB page I have a list of incidents with two elements:

ArnoudKooi_0-1682501259805.png

On every update the client state parameter gets build up:

 

{
    "4045362fdbcb8910f0ff4e68139619a4": {
        "short_description": "RANDOM TESTDATA ",
        "active": true
    },
    "1eaecf121beb3410ba6a437cbc4bcb28": {
        "short_description": "new value"
    }
}

 

When you implement a save button, you can iterate over that object. on update your records

Hi Arnold,

 

Thanks, nice idea to save only the updated data this way, it makes the JSON easier to navigate then saving / having to access all the repeater data, i was too focused trying to do that.

 

I'll probably apply this using a custom event set on the body, so that i can pass the elementId inside the payload of an event, as a parameter, instead of relying ot the element ID. Every component call this custom event with fieldName, sys_id and newValue, and then i update the client state on body event handler. But that's just a personal taste, your idea is what makes it work.

 

I'll accept the answer as a solution.