Module 4: Understanding Entry Points

Week 3 • NetSuite SuiteScript 2.0 Training • ~60 minutes

🎯 Learning Objectives

By the end of this module, you will be able to:

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.

💡 Key Concept

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

EnvironmentRuns OnScript TypesKey Characteristic
Client-SideUser's browserClient ScriptUser is interacting with form
Server-SideNetSuite serversUser 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)
└─────────────────┘
⚠️ Critical Understanding

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 PointTriggers WhenReturn Value
pageInitPage loadsNone
fieldChangedField value changesNone
postSourcingAfter sourcing completesNone
validateFieldBefore leaving fieldBoolean
lineInitSublist line selectedNone
validateLineBefore committing lineBoolean
validateInsertBefore inserting lineBoolean
validateDeleteBefore deleting lineBoolean
sublistChangedAfter sublist changeNone
saveRecordBefore saveBoolean

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
🚫 Why This Matters

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

ValueUser Action
context.UserEventType.CREATECreating new record
context.UserEventType.EDITEditing existing record
context.UserEventType.DELETEDeleting record
context.UserEventType.VIEWViewing record (beforeLoad only)
context.UserEventType.COPYCopying record
context.UserEventType.XEDITInline edit

6. Debugging Client-Side Scripts

Using Browser Developer Tools

For client-side scripts, use your browser's built-in debugger (F12 in Chrome):

  1. Open the record in NetSuite
  2. Press F12 to open Developer Tools
  3. Go to Sources tab
  4. Find your script file
  5. Set breakpoints by clicking line numbers
  6. 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)
}
⚠️ Cache Issues

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

Exercise 1: Client Script Basics

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
Exercise 2: User Event Script

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
Exercise 3: Execution Order

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 beforeSubmit for validation; afterSubmit for notifications
  • Always check context.type to 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