Managing large sublists, such as the Sales Order Item sublist, can be challenging, especially when scrolling through numerous rows. Freezing the header and first column provides a better user experience by keeping key information in view as you scroll horizontally or vertically. Here is a solution that achieves this using a combination of User Event Script (UES) and Client Script (CS).
Key Features of the Solution
- Freezing the Header Row: Keeps column headers visible while scrolling vertically.
- Freezing the First Column: Ensures the first column remains visible while scrolling horizontally.
- Dynamic Height Adjustment: Automatically adjusts the sublist container’s height to fit within the viewport.
Implementation: Scripts Overview
The solution involves two scripts:
- User Event Script (UES): Injects the required HTML and JavaScript for freezing functionality into the form during the
beforeLoadevent. - Client Script (CS): Initializes the freezing behavior on the page and line-level initialization.
UserEventScript
This script adds the custom JavaScript and jQuery-based logic to the Sales Order form during the beforeLoad event.
Key Functions:
Injecting JavaScript Logic: Adds an inline HTML field to embed a script for freezing the header and column.
Dynamic Styling: Adjusts the height of the container to optimize the scrolling area.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/record', 'N/search', 'N/ui/serverWidget'],
/**
* @param{record} record
* @param{search} search
* @param{serverWidget} serverWidget
*/
(record, search, serverWidget) => {
/**
* Defines the function definition that is executed before record is loaded.
* @param {Object} scriptContext
* @param {Record} scriptContext.newRecord - New record
* @param {string} scriptContext.type - Trigger type; use values from the context.UserEventType enum
* @param {Form} scriptContext.form - Current form
* @param {ServletRequest} scriptContext.request - HTTP request information sent from the browser for a client action only.
* @since 2015.2
*/
const beforeLoad = (scriptContext) => {
try {
// Set the client script file using the file path
scriptContext.form.clientScriptModulePath = './jj_cs_freeze_header.js'; // Replace with your actual file path
let htmlString =
'<script>' +
' function freezeHeadAndColumn() {' +
' (function ($, undefined) {' +
' $(function () {' +
' const windowHeight = $(window).height();' +
' const container = $('.uir-machine-table-container');' +
// Set container height for scrollable area
' if (container.height() < windowHeight) {' +
' container.css('height', 'auto');' +
' } else {' +
' container.css('height', '70vh');' +
' }' +
' container.bind('scroll', (event) => {' +
' const headerElem = $(event.target).find('.uir-machine-headerrow, .uir-list-headerrow');' +
// Freeze header row
' headerElem.css('transform', `translate(0, ${event.target.scrollTop}px)`);' +
' const rows = $(event.target).find('table tr');' +
' rows.each((index, row) => {' +
' const firstCell = $(row).find('th:first-child, td:first-child');' +
// Freeze first column
' firstCell.css('transform', `translate(${event.target.scrollLeft}px, 0)`);' +
' });' +
' });' +
' });' +
' })(window.jQuery);' +
' }' +
' freezeHeadAndColumn();' +
'</script>';
scriptContext.form.addField({
type: 'inlinehtml',
id: 'custpage_stickyheaders_script',
label: 'Hidden'
}).defaultValue = htmlString;
} catch (err) {
log.debug("error@beforeLoad", err);
}
}
return { beforeLoad }
});
ClientScript
This script ensures that the freezing behavior is activated during the pageInit and lineInit events.
Key Functions:
pageInit Event: Runs the freezing logic when the form loads.
lineInit Event: Ensures the freezing logic applies to inline sublist edits.
/**
* @NApiVersion 2.x
* @NScriptType ClientScript
* @NModuleScope SameAccount
*/
define(['N/record'],
/**
* @param{record} record
*/
function(record) {
function activateFreeze(context) {
freezeHeadAndColumn();
}
return {
pageInit: activateFreeze,
lineInit: activateFreeze
};
});