Multiple select field in a sublist
Ever since we were little kids we dreamt of one thing and one thing only - being an astronaut.
Now that we are older and too out of shape to ever fulfill the dream of being launched into space in a pod attached to highly flammable fuel cells, we have to take solace in fulfilling slightly more mundane dreams - like the dream of having a multi-select field in a sublist.
As usual, the point of official documentation is to destroy our dreams from the get-go.
The DATETIME, FILE, HELP, INLINEHTML, LABEL, LONGTEXT, MULTISELECT, RADIO and RICHTEXT values are not supported with this method.
I refuse to be discouraged by official documentation or by gorrilion enhancement requests and - to my great pleasure - my sentiment towards this issue is shared by my childhood hero.
His answer when he learned that you can't have multi-select fields in a sublist?
So there we have it. We can get to work.
First we're gonna need a nice little Transaction Line field of type Text Area.
Then we add a little client script that needs only two entry points - pageInit and validateLine. Let's start with our pageInit function.
function pageInit(scriptContext) {
try
{
}
catch (error)
{
log.error({title: 'pageInit', details: error});
}
}
First of all, we create our own multi-select element. Give it some nice id of your choosing and never forget to set it as multiple.
function pageInit(scriptContext) {
try
{
let selectField = document.createElement('select');
selectField.multiple = true;
selectField.setAttribute('id', 'cust_select');
}
catch (error)
{
log.error({title: 'pageInit', details: error});
}
}
Then, through some DOM manipulation, we hide the custom field we created in step one. You are of course aware that manipulating DOM may lead to issues if NetSuite ever decides to change their DOM structure, so I won't even bring that up.
function pageInit(scriptContext) {
try
{
let selectField = document.createElement('select');
selectField.multiple = true;
selectField.setAttribute('id', 'cust_select');
document.getElementById('custcol_multiple_select').style.display = 'none';
}
catch (error)
{
log.error({title: 'pageInit', details: error});
}
}
Then let's gather the data that will make up our options for the multi-select field. I don't know what data you want to display, so for this purpose I just loaded employees through a saved search.
And for each employee (I only get internal ID and their name) we create an option element, which will be appended to the selectField we have created in previous step.
function pageInit(scriptContext) {
try
{
let selectField = document.createElement('select');
selectField.multiple = true;
selectField.setAttribute('id', 'cust_select');
document.getElementById('custcol_multiple_select').style.display = 'none';
let employeeData = getEmployees();
employeeData.forEach(employee => {
let option = document.createElement('option');
option.setAttribute('value', employee.id);
option.innerText = employee.name;
selectField.appendChild(option);
});
}
catch (error)
{
log.error({title: 'pageInit', details: error});
}
}
Our final job in pageInit is to replace our Text Area field from the first step with the selectField element and all its options.
function pageInit(scriptContext) {
try
{
let selectField = document.createElement('select');
selectField.multiple = true;
selectField.setAttribute('id', 'cust_select');
document.getElementById('custcol_multiple_select').style.display = 'none';
let employeeData = getEmployees();
employeeData.forEach(employee => {
let option = document.createElement('option');
option.setAttribute('value', employee.id);
option.innerText = employee.name;
selectField.appendChild(option);
});
let parentField = document.getElementById('item_custcol_multiple_select_fs');
parentField.appendChild(selectField);
}
catch (error)
{
log.error({title: 'pageInit', details: error});
}
}
In case you don't know what the actual ID of the parent element is, you may have to find it through the developer console. Its ID will be quite similar to your custom field's internal ID, but will likely include some prefix and _fs suffix. Plus it's actually gonna be right above your custom field. In this case the ID is item_custcol_multiple_select_fs.
There we go, you should now see a cute little multi-select field that has a list of whatever you need to multiply select from.
But our job is not done just yet. We still need to get the values and store them somewhere. Which leads us to the validateLine function.
function validateLine(scriptContext) {
try
{
return true;
}
catch (error)
{
log.error({title: 'validateLine', details: error});
}
}
Apart from obiously getting the current record, we get all the child nodes of our custom select element we created in pageInit function.
We define some displayResults, that will be displayed when you save the record/line. They will be in text form, since our main custom field is of type Text Area.
function validateLine(scriptContext) {
try
{
let currentRec = scriptContext.currentRecord;
let options = document.getElementById('cust_select').childNodes;
let displayResults = '';
return true;
}
catch (error)
{
log.error({title: 'validateLine', details: error});
}
}
Then we go through all the options and write the ones that were selected into the displayResults.
function validateLine(scriptContext) {
try
{
let currentRec = scriptContext.currentRecord;
let options = document.getElementById('cust_select').childNodes;
let displayResults = '';
options.forEach(option => {
if (option.selected)
{
displayResults += option.innerText + '\n';
}
});
return true;
}
catch (error)
{
log.error({title: 'validateLine', details: error});
}
}
Finally we set the displayResults into our main custom field.
function validateLine(scriptContext) {
try
{
let currentRec = scriptContext.currentRecord;
let options = document.getElementById('cust_select').childNodes;
let displayResults = '';
options.forEach(option => {
if (option.selected)
{
displayResults += option.innerText + '\n';
}
});
currentRec.setCurrentSublistValue({
sublistId: 'item',
fieldId: 'custcol_multiple_select',
value: displayResults,
ignoreFieldChange: false
});
return true;
}
catch (error)
{
log.error({title: 'validateLine', details: error});
}
}
And here we are. All done. One more dream to cross off your list. Was it worth it?