Marc
06/04/2025, 11:01 AMitem
sublist. It works perfectly for committed lines — the dropdown appears in the last column and updates the hidden custcol_task_project
field as expected.
However, I’m having trouble getting it to appear on non-committed lines (i.e., the current line being edited).
Even though I’m injecting the <select>
during lineInit
and also trying to target the current editing line, the dropdown doesn’t render properly, or I can't click it — sometimes it flickers or disappears when the user interacts with the row.
Do you know of a clean or reliable way to:
• Display custom UI elements (like a <select>
dropdown) directly in the current editable sublist line;
• Ensure the dropdown is interactive even before the line is committed?
/**
* @NApiVersion 2.1
* @NScriptType ClientScript
*/
define(['N/currentRecord', 'N/search'], function (currentRecord, search) {
const FIELD_JOB = 'job';
const SUBLIST_ID = 'item';
const FIELD_TASK = 'custcol_task_project';
let cachedTasks = [];
function pageInit() {
const rec = currentRecord.get();
const projectId = rec.getValue({ fieldId: FIELD_JOB });
if (!projectId) return;
fetchTasks(projectId).then(tasks => {
cachedTasks = tasks;
injectAllVisibleLines(rec);
});
}
function lineInit() {
setTimeout(() => {
const rec = currentRecord.get();
const rows = document.querySelectorAll(`tr[id^="item_row_"]`);
rows.forEach(row => injectSelectInLastCell(row, rec));
injectOnCurrentEntryLine(rec);
}, 150);
}
function injectAllVisibleLines(rec) {
const rows = document.querySelectorAll(`tr[id^="item_row_"]`);
rows.forEach(row => injectSelectInLastCell(row, rec));
injectOnCurrentEntryLine(rec);
}
function injectOnCurrentEntryLine(rec) {
const inputField = document.querySelector(`input[name$="${FIELD_TASK}"]`);
if (!inputField) return;
const row = inputField.closest('tr');
if (!row || row.querySelector('.project-task-select')) return;
injectSelectInLastCell(row, rec);
}
function injectSelectInLastCell(row, rec) {
if (!row || row.querySelector('.project-task-select')) return;
const cells = row.querySelectorAll('td');
if (cells.length === 0) return;
const targetCell = cells[cells.length - 1]; // 🟩 DERNIÈRE COLONNE
const wrapper = document.createElement('div');
wrapper.className = 'project-task-select';
wrapper.style = 'margin-top:3px;background:#fff8cc;padding:2px;border:1px solid #ccc;';
const select = document.createElement('select');
select.style = 'width:100%;font-size:10px;';
const empty = document.createElement('option');
empty.value = '';
empty.text = '-- Select Task --';
select.appendChild(empty);
cachedTasks.forEach(task => {
const opt = document.createElement('option');
opt.value = task.id;
opt.text = task.name;
select.appendChild(opt);
});
// Pré-sélection basée sur champ réel
const taskField = row.querySelector(`input[name$="${FIELD_TASK}"]`);
if (taskField && taskField.value) {
select.value = taskField.value;
}
select.addEventListener('change', () => {
try {
const allRows = document.querySelectorAll(`tr[id^="item_row_"]`);
let lineIndex = -1;
allRows.forEach((r, i) => {
if (r === row) lineIndex = i;
});
if (lineIndex === -1) {
rec.setCurrentSublistValue({
sublistId: SUBLIST_ID,
fieldId: FIELD_TASK,
value: select.value
});
console.log(`📝 Ligne en cours mise à jour`);
} else {
rec.selectLine({ sublistId: SUBLIST_ID, line: lineIndex });
rec.setCurrentSublistValue({
sublistId: SUBLIST_ID,
fieldId: FIELD_TASK,
value: select.value
});
rec.commitLine({ sublistId: SUBLIST_ID });
console.log(`☑️ Ligne ${lineIndex} enregistrée`);
}
} catch (e) {
console.warn('❌ Erreur lors du commit', e);
}
});
wrapper.appendChild(select);
targetCell.appendChild(wrapper); // 👉 ON N'ÉCRASE PAS LE CONTENU NATIF
}
function fetchTasks(projectId) {
const results = [];
const taskSearch = search.create({
type: 'projecttask',
filters: [['company', 'anyof', projectId]],
columns: ['internalid', 'title']
});
return new Promise(resolve => {
taskSearch.run().each(result => {
results.push({
id: result.getValue({ name: 'internalid' }),
name: result.getValue({ name: 'title' })
});
return true;
});
resolve(results);
});
}
return { pageInit, lineInit };
});
Celigo AI
06/04/2025, 11:01 AMAI generated answer (using internal Slack threads):Based on the conversations, it seems like you're trying to manipulate the DOM directly to inject a custom dropdown into the sublist line being edited. This approach can be problematic due to the way NetSuite redraws the current line multiple times, which can cause issues with your custom UI elements. Unfortunately, NetSuite's client-side API doesn't provide a clean way to inject custom UI elements into the current editable sublist line. The
lineInit
function is designed to initialize the line for editing, but it doesn't provide a way to manipulate the UI directly.
One workaround could be to use a Suitelet to create a custom form with your desired functionality. You can then redirect the user to this Suitelet when they need to edit a line in the sublist. This would give you full control over the UI and allow you to implement the desired functionality.
Another approach could be to use a client script to listen for changes to the sublist line and then update the custcol_task_project
field accordingly. This wouldn't allow you to display a custom dropdown in the sublist line, but it would ensure that the field is updated correctly.
Here's a sample code snippet that demonstrates this approach:
javascript
function lineInit(context) {
var currentRecord = context.currentRecord;
var sublistName = context.sublistId;
if (sublistName === 'item') {
var lineCount = currentRecord.getLineCount({
sublistId: sublistName
});
for (var i = 0; i < lineCount; i++) {
var taskProject = currentRecord.getSublistValue({
sublistId: sublistName,
fieldId: 'custcol_task_project',
line: i
});
// Update the 'custcol_task_project' field based on the selected option in the dropdown
// ...
}
}
}
Remember to replace the ...
with your own logic for updating the custcol_task_project
field based on the selected option in the dropdown.
Please note that this is a workaround and may not provide the exact functionality you're looking for. It's always a good idea to test thoroughly and consider the user experience when implementing customizations like this.
******
Disclaimer:
This response was generated by an artificial intelligence assistant based on previous conversations from multiple Slack channels, and may contain inaccuracies or mistakes.
******Celigo AI
06/04/2025, 11:02 AMSlack thread 1: here (available only if the original thread was posted in the last 90 days)
Similarity score: 0.831252515
Slack thread 2: here (available only if the original thread was posted in the last 90 days)
Similarity score: 0.828072488
Slack thread 3: here (available only if the original thread was posted in the last 90 days)
Similarity score: 0.824786603
Celigo AI
06/04/2025, 11:02 AM