📑 In This Module
🎯 Learning Objectives
By the end of this module, you will be able to:
- Understand what entry points are and when each triggers
- Distinguish between client-side and server-side entry points
- Map user actions to specific entry point functions
- Choose the right entry point for your automation needs
- Debug client-side scripts using browser developer tools
- Understand the complete record lifecycle from load to save
1. What Are Entry Points?
An entry point is a trigger that determines when your script executes. Think of entry points as "hooks" that NetSuite provides for you to insert your custom logic at specific moments during user interactions.
Every entry point is tied to a specific user action or system event. Understanding when each triggers is crucial for placing your code in the right location.
The Two Environments
| Environment | Runs On | Script Types | Key Characteristic |
|---|---|---|---|
| Client-Side | User's browser | Client Script | User is interacting with form |
| Server-Side | NetSuite servers | User Event, Scheduled, Map/Reduce, etc. | Processing on backend |
2. The Complete Execution Flow
When a user interacts with a record, entry points fire in a specific order:
User opens record
│
▼
┌─────────────────┐
│ beforeLoad │ ← Server-side (User Event)
└────────┬────────┘
│
▼ (Page loads in browser)
┌─────────────────┐
│ pageInit │ ← Client-side (runs once when page loads)
└────────┬────────┘
│
User makes changes...
│
┌─────────────────┐
│ fieldChanged │ ← Client-side (each field change)
│ validateField │
│ postSourcing │
└────────┬────────┘
│
User clicks Save
│
┌─────────────────┐
│ saveRecord │ ← Client-side (can cancel save)
└────────┬────────┘
│
Data sent to server
│
┌─────────────────┐
│ beforeSubmit │ ← Server-side (before database write)
└────────┬────────┘
│
Record saved to database
│
┌─────────────────┐
│ afterSubmit │ ← Server-side (after database write)
└─────────────────┘
Client-side scripts only run when the user is directly interacting with the form (create, edit, copy). They do NOT run when viewing a record or when records are modified via other means (imports, workflows, other scripts).
3. Client-Side Entry Points
pageInit
Fires once when the page completely loads. Use for initial setup.
/**
* @NScriptType ClientScript
*/
define(['N/log'], function(log) {
function pageInit(context) {
// context.mode = 'create', 'edit', or 'copy'
log.debug('Page Init', 'Mode: ' + context.mode);
if (context.mode === 'create') {
// Set default values for new records
context.currentRecord.setValue({
fieldId: 'custbody_source',
value: 'Web'
});
}
}
return { pageInit: pageInit };
});
fieldChanged
Fires after a field value changes and the user moves to another field.
function fieldChanged(context) {
var fieldId = context.fieldId;
var currentRecord = context.currentRecord;
if (fieldId === 'custbody_discount_pct') {
var discount = currentRecord.getValue('custbody_discount_pct');
var subtotal = currentRecord.getValue('subtotal');
// Calculate and set discount amount
currentRecord.setValue({
fieldId: 'custbody_discount_amt',
value: subtotal * (discount / 100)
});
}
}
validateField
Fires before leaving a field. Return false to keep focus on the field.
function validateField(context) {
if (context.fieldId === 'custbody_discount_pct') {
var discount = context.currentRecord.getValue('custbody_discount_pct');
if (discount > 50) {
alert('Discount cannot exceed 50%');
return false; // Keeps cursor in field
}
}
return true; // Allow leaving field
}
saveRecord
Fires when user clicks Save. Return false to cancel the save.
function saveRecord(context) {
var rec = context.currentRecord;
var email = rec.getValue('email');
if (!email) {
alert('Email is required!');
return false; // Cancels save
}
return true; // Allows save to proceed
}
Complete Client Script Entry Points
| Entry Point | Triggers When | Return Value |
|---|---|---|
pageInit | Page loads | None |
fieldChanged | Field value changes | None |
postSourcing | After sourcing completes | None |
validateField | Before leaving field | Boolean |
lineInit | Sublist line selected | None |
validateLine | Before committing line | Boolean |
validateInsert | Before inserting line | Boolean |
validateDelete | Before deleting line | Boolean |
sublistChanged | After sublist change | None |
saveRecord | Before save | Boolean |
4. Server-Side Entry Points (User Event)
beforeLoad
Fires before the record is displayed to the user. Use for UI modifications.
function beforeLoad(context) {
// context.type tells us what the user is doing
if (context.type === context.UserEventType.VIEW) {
// Hide a button when viewing
context.form.removeButton('custpage_approve');
}
if (context.type === context.UserEventType.CREATE) {
// Add a custom button
context.form.addButton({
id: 'custpage_validate',
label: 'Validate Address',
functionName: 'validateAddress'
});
}
}
beforeSubmit
Fires after user submits but BEFORE saving to database. Use for validation and data cleanup.
function beforeSubmit(context) {
var newRecord = context.newRecord;
// Validate data before it's saved
var total = newRecord.getValue('total');
if (total > 100000) {
throw Error('Orders over $100,000 require manager approval');
}
// Clean up data
var phone = newRecord.getValue('phone');
newRecord.setValue({
fieldId: 'phone',
value: phone.replace(/[^0-9]/g, '') // Remove non-digits
});
}
afterSubmit
Fires AFTER the record is saved to database. Use for follow-up actions.
function afterSubmit(context) {
if (context.type !== context.UserEventType.CREATE) return;
var newRecord = context.newRecord;
var customerId = newRecord.getValue('entity');
// Send welcome email to new customer
email.send({
author: -5, // Employee ID
recipients: customerId,
subject: 'Order Confirmation',
body: 'Thank you for your order #' + newRecord.id
});
}
5. beforeSubmit vs afterSubmit
This is one of the most important distinctions to understand:
✅ Use beforeSubmit For:
- Data validation
- Field value cleanup/formatting
- Setting calculated values
- Preventing invalid saves
- Anything that should block the save
✅ Use afterSubmit For:
- Sending notifications/emails
- Creating related records
- External API calls
- Logging/auditing
- Actions that need the record ID
If you send a confirmation email in beforeSubmit and then the save fails, the customer gets a confirmation for an order that doesn't exist! Always send notifications in afterSubmit where you're guaranteed the record was saved.
context.type Values
| Value | User Action |
|---|---|
context.UserEventType.CREATE | Creating new record |
context.UserEventType.EDIT | Editing existing record |
context.UserEventType.DELETE | Deleting record |
context.UserEventType.VIEW | Viewing record (beforeLoad only) |
context.UserEventType.COPY | Copying record |
context.UserEventType.XEDIT | Inline edit |
6. Debugging Client-Side Scripts
Using Browser Developer Tools
For client-side scripts, use your browser's built-in debugger (F12 in Chrome):
- Open the record in NetSuite
- Press F12 to open Developer Tools
- Go to Sources tab
- Find your script file
- Set breakpoints by clicking line numbers
- Trigger the entry point (e.g., change a field)
Using console.log
function fieldChanged(context) {
console.log('Field changed:', context.fieldId);
console.log('New value:', context.currentRecord.getValue(context.fieldId));
// Output appears in browser console (F12)
}
Browsers cache JavaScript files. After updating your script, always press Ctrl+F5 (Windows) or Cmd+Shift+R (Mac) to force a fresh reload.
Using the debugger Statement
function saveRecord(context) {
debugger; // Browser will pause here if DevTools is open
var rec = context.currentRecord;
// Step through code line by line
return true;
}
🏋️ Practice Exercises
Create a Client Script on the Customer record that:
- On
pageInit: Logs the current mode (create/edit) - On
fieldChanged: When phone changes, logs the new value - On
saveRecord: Requires email to be filled in
Create a User Event Script on the Sales Order that:
- On
beforeSubmit: Prevents orders under $100 - On
afterSubmit: Logs "Order created: [ID]" for new orders
Create both a Client Script and User Event Script on the same record. Add log.debug or console.log statements to each entry point. Save the record and trace the complete execution order.
🎯 Key Takeaways
- Entry points are triggers tied to specific user actions
- Client-side scripts run in the browser; server-side run on NetSuite servers
- Client scripts only fire on create, edit, copy - NOT view
- Use
beforeSubmitfor validation;afterSubmitfor notifications - Always check
context.typeto filter when your code should run - Use Ctrl+F5 to clear browser cache when testing client scripts
- Execution order: beforeLoad → pageInit → field events → saveRecord → beforeSubmit → afterSubmit