- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-21-2023 09:30 AM - edited 04-22-2023 03:12 AM
Hi,
I have a repeater that looks somewhat like a survey:
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
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-26-2023 02:29 AM - edited 04-26-2023 04:04 AM
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:
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-27-2023 03:18 AM
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.
2) Call this event everytime someone select/change value in an input field, and pass the three properties above.
3) Update the client state parameter with the event handler on the body with a script very similar to yours.
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-24-2023 03:45 AM
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.
ServiceNow Community Rising Star 2022/2023
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-26-2023 02:28 AM
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-26-2023 02:29 AM - edited 04-26-2023 04:04 AM
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:
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-26-2023 03:34 AM
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.