setting values in beforeLoad
So, you have decided to set/update a field value when user views a record. You probably have a very good reason to do so; perhaps there are some data that change very often and you want to have the most up-to-date information. Maybe the data isn't important at all, in fact they are not even important enough to mass update your records to show them, but you want to show them anyway, in case users stumble upon the record.
Whatever the case may be, I am not here to judge, merely to show you how it's done.
According to the official documentation, you cannot manipulate data for records that are loaded in beforeLoad scripts.
Data cannot be manipulated for records that are loaded in beforeLoad scripts. If you attempt to update a record loaded in beforeLoad, the logic is ignored.
Personally, I am not sure I agree with this very definitive statement, so I invited an independent consultant to shed some more light on this matter.
What do you think, Simon?
Well, there you have it.
The most common approach to setting values before the record is loaded is to just set values through record.setValue() function. This doesn't work, because you are not saving the record, therefore the values won't be updated when the record is finally loaded. So, some people call record.save() after the changes are done. But this will result in the funny little error "Record has been changed".
And that's about the point where you likely went "fuck it, it's just not possible".
But it is. Let's get down to business, we both know you are only here to copy the code anyway, so here it is:
define(['N/log', 'N/record', 'N/redirect'],
(log, record, redirect) => {
const beforeLoad = (scriptContext) => {
if (scriptContext.type == scriptContext.UserEventType.VIEW)
{
let urlParams = scriptContext.request.parameters;
log.audit('urlParams', urlParams);
if (!urlParams.refresh)
{
let rec = record.load({
type: scriptContext.newRecord.type,
id: scriptContext.newRecord.id,
isDynamic: false
});
/*
do your thing here
*/
rec.save();
// Alternatively:
record.submitFields({
id: scriptContext.newRecord.id,
type: scriptContext.newRecord.type,
values: {
'fieldid1': value1,
'fieldid2': value2,
}
});
redirect.toRecord({
type: scriptContext.newRecord.type,
id: scriptContext.newRecord.id,
parameters: {'refresh':'true'}
});
}
}
}
return {beforeLoad}
});
Now, onto the explanation.
First, we will limit the scope to View mode only. If you won't use this script for anything else, you can also limit the scope in the script deployment record, by setting the Event Type to View, which means you won't need this condition.
if (scriptContext.type == scriptContext.UserEventType.VIEW)
Then, we will get the URL parameters from the scriptContext, because they are quite crucial part of this approach.
let urlParams = scriptContext.request.parameters;
We will check whether the URL parameters contain the key 'refresh' and as long as they don't, we will load the very same record we are about to view and execute the rest of the logic.
if (!urlParams.refresh)
{
let rec = record.load({
type: scriptContext.newRecord.type,
id: scriptContext.newRecord.id,
isDynamic: false
});
/*
whatever logic you need, it goes here
*/
}
Once you do your thing to get your desired value(s), you can either do record.save() or - in case you only needed to set header level values - you can call record.submitFields(), where the values are in an object containing key:value pairs of your fields and their new values.
Goes without saying that if you need to update sublist values, you will need to do the whole record.load() » record.save() dance; while if you are only setting header level values, record.submitFields() is all you need.
record.submitFields({
id: scriptContext.newRecord.id,
type: scriptContext.newRecord.type,
values: {
'fieldid1': value1,
'fieldid2': value2,
}
});
When the values are submitted / record saved, we will actually redirect to the very same record we are attempting to view, but we set the URL parameter 'refresh' to true, so we are not stuck in an infinite loop of setting values and redirecting - our code will only execute when the 'refresh' parameter is false, or rather when it is missing entirely.
redirect.toRecord({
type: scriptContext.newRecord.type,
id: scriptContext.newRecord.id,
parameters: {'refresh':'true'}
});
Without redirecting to the same record, you will get the error message that Record has been changed. Redirecting takes care of this.
What is the downside? I suppose slightly longer load time when users initially load the record, but that very much depends on the complexity of the operations you execute before saving the record. Also, record.save() takes noticably longer than record.submitFields(), so be on the lookout.