🔹 Introduction
Client Scripts run in the browser while users interact with NetSuite forms. They’re perfect for improving UX: show prompts, auto-fill fields, validate inputs, and control sublist behavior.
🔹 Supported Entry Points (When each one runs)
- pageInit — when the form loads (view/edit/create).
- saveRecord — just before the record is saved.
- validateField — when a field is changed (before the value is accepted).
- fieldChanged — immediately after a field value changes.
- postSourcing — after NetSuite “sources” a field (populates a value automatically).
- validateLine — before committing a sublist line.
- sublistChanged — after a sublist line is added/edited/removed.
🔹 Example 1: Page Init Alert (welcome message)
What this script does (in plain English):
- Shows a friendly popup the moment the form opens, confirming that your Client Script is running.
When it’s useful:
- Quick sanity check during development, or to show brief instructions to users.
/**
*@NApiVersion 2.1
*@NScriptType ClientScript
*/
define([], () => {
const pageInit = () => {
// Runs when the form loads (create/edit/view)
alert('Welcome to NetSuite! This record just opened.');
};
return { pageInit };
});
How it works:
- NetSuite calls
pageInit()
automatically on load. - The
alert()
shows a message to the user.
Deploy on: Any record you want to test (e.g., Customer).
🔹 Example 2: Validate Field (email format)
What this script does:
- When a user edits the Email field, it checks the value.
- If it doesn’t look like an email, it blocks the change and asks the user to fix it.
Why it’s helpful:
- Prevents bad data entry before the record is saved.
/**
*@NApiVersion 2.1
*@NScriptType ClientScript
*/
define(['N/currentRecord'], (currentRecord) => {
const validateField = (context) => {
// Triggered when a field changes, before NetSuite accepts the value
if (context.fieldId === 'email') {
const rec = currentRecord.get();
const email = rec.getValue('email') || '';
// Very simple check; replace with robust regex if needed
if (!email.includes('@') || !email.includes('.')) {
alert('Please enter a valid email address.');
return false; // stops the change
}
}
return true; // allow the change
};
return { validateField };
});
How it works:
validateField
receives thefieldId
being edited.- If the field is
email
, we read the value and perform a simple check. - Returning
false
cancels the change.
Deploy on: Customer (or any record with an Email field).
🔹 Example 3: Validate Record Before Save (required phone)
What this script does:
- When the user tries to save, it ensures Phone is filled.
- If not, it blocks the save and shows a message.
Why it’s helpful:
- Ensures critical fields are populated without relying on server-side errors.
/**
*@NApiVersion 2.1
*@NScriptType ClientScript
*/
define(['N/currentRecord'], (currentRecord) => {
const saveRecord = () => {
// Triggered when the user clicks Save
const rec = currentRecord.get();
const phone = rec.getValue('phone');
if (!phone) {
alert('Phone number is required!');
return false; // prevent save
}
return true; // allow save
};
return { saveRecord };
});
How it works:
saveRecord()
runs right before submit.- Returning
false
cancels the save.
Deploy on: Customer, Vendor, Lead, etc.
🔹 Example 4: Sublist Validation (quantity > 0)
What this script does:
- On the Items sublist (e.g., Sales Order), it blocks committing a line if Quantity ≤ 0.
Why it’s helpful:
- Stops user mistakes on line entries (negative/zero quantities).
/**
*@NApiVersion 2.1
*@NScriptType ClientScript
*/
define(['N/currentRecord'], (currentRecord) => {
const validateLine = (context) => {
// Runs before committing a line to a sublist
if (context.sublistId === 'item') {
const rec = currentRecord.get();
const qty = rec.getCurrentSublistValue({
sublistId: 'item',
fieldId: 'quantity'
});
if (qty <= 0) {
alert('Quantity must be greater than zero.');
return false; // block committing the line
}
}
return true; // allow line commit
};
return { validateLine };
});
How it works:
- Uses
getCurrentSublistValue
to read the in-progress line. - Returning
false
prevents the line from being added.
Deploy on: Sales Order, Invoice, Quote—any record with item
sublist.
🔹 Example 5: React After a Field Changes (auto-fill memo)
What this script does:
- When Entity/Customer is selected on a Sales Order, it auto-fills Memo with a friendly note.
Why it’s helpful:
- Saves clicks and standardizes descriptions for reporting/searching later.
/**
*@NApiVersion 2.1
*@NScriptType ClientScript
*/
define(['N/currentRecord'], (currentRecord) => {
const fieldChanged = (context) => {
// Runs immediately after a field's value changes
if (context.fieldId === 'entity') {
const rec = currentRecord.get();
rec.setValue({
fieldId: 'memo',
value: 'Memo set automatically after customer selection'
});
}
};
return { fieldChanged };
});
How it works:
fieldChanged
fires after the change is applied.- We set another field (
memo
) as a follow-up action.
Deploy on: Sales Order.
🔹 Example 6: Post-Sourcing Hook (after NetSuite fills fields)
What this script does:
- After NetSuite auto-sources dependent fields (e.g., location after subsidiary), we log or tweak other fields.
Why it’s helpful:
- Ideal for logic that depends on values NetSuite fills in automatically.
/**
*@NApiVersion 2.1
*@NScriptType ClientScript
*/
define(['N/currentRecord'], (currentRecord) => {
const postSourcing = (context) => {
// Runs after sourcing completes for a field
if (context.fieldId === 'subsidiary') {
const rec = currentRecord.get();
const subsidiary = rec.getValue('subsidiary');
// Example: write a quick note for the user
rec.setValue({
fieldId: 'custbody_internal_note',
value: `Subsidiary selected: ${subsidiary}`
});
}
};
return { postSourcing };
});
How it works:
- Fires after NetSuite has finished auto-populating related fields.
- Safest place to act on sourced values.
Deploy on: Transactions that source fields (SO/PO/Invoice).
🔹 Best Practices (Beginner-friendly)
- Keep it light: Heavy logic belongs in User Event/Scheduled/Map-Reduce (server).
- Fail fast, explain clearly: Use small, specific alerts. Don’t overwhelm users.
- Test in Sandbox: Then move to Production with controlled deployments.
- Name clearly:
CS_ValidateEmail.js
,CS_SO_AutoMemo.js
—future you will thank you. - Combine validations wisely:
validateField
for field-level checks;saveRecord
as a final gate.
âś… Key Takeaway
Client Scripts give you immediate control over form interactions: validate inputs, guide users, and prevent common mistakes right in the browser. Once you’re comfortable here, move on to User Event and Scheduled/Map-Reduce for server-side power.
Leave a Reply