- ERPNext Client Scripts Syntax (EN)
- Client Scripts run in the browser and control all UI interactions in ERPNext/Frappe. They are created via
- Setup → Client Script
- or in custom apps under
- public/js/
- .
- Version
- v14/v15/v16 compatible (unless noted otherwise)
Quick Reference
Basic Structure
frappe
.
ui
.
form
.
on
(
'DocType Name'
,
{
// Form-level events
setup
(
frm
)
{
}
,
refresh
(
frm
)
{
}
,
validate
(
frm
)
{
}
,
// Field change events
fieldname
(
frm
)
{
}
}
)
;
Most Used Patterns
Action
Code
Set value
frm.set_value('field', value)
Hide field
frm.toggle_display('field', false)
Make field mandatory
frm.toggle_reqd('field', true)
Call server
frappe.call({method: 'path.to.method', args: {}})
Prevent save
frappe.throw('Error message')
Event Selection
Which event should I use?
One-time setup (queries, defaults)?
└── setup
Show/hide UI, add buttons?
└── refresh
Validation before save?
└── validate
Do something right after save?
└── after_save
React to field change?
└── {fieldname}
→ See
references/events.md
for complete event list and execution order.
Essential Methods
Value Manipulation
// Set single value (async, returns Promise)
frm
.
set_value
(
'status'
,
'Approved'
)
;
// Set multiple values at once
frm
.
set_value
(
{
status
:
'Approved'
,
priority
:
'High'
}
)
;
// Get value
let
value
=
frm
.
doc
.
fieldname
;
Field Properties
// Show/hide
frm
.
toggle_display
(
'priority'
,
condition
)
;
// Make mandatory
frm
.
toggle_reqd
(
'due_date'
,
true
)
;
// Make read-only
frm
.
toggle_enable
(
'amount'
,
false
)
;
// Advanced property change
frm
.
set_df_property
(
'status'
,
'options'
,
[
'New'
,
'Open'
,
'Closed'
]
)
;
frm
.
set_df_property
(
'amount'
,
'read_only'
,
1
)
;
Link Field Filters
// Simple filter
frm
.
set_query
(
'customer'
,
(
)
=>
(
{
filters
:
{
disabled
:
0
}
}
)
)
;
// Filter in child table
frm
.
set_query
(
'item_code'
,
'items'
,
(
doc
,
cdt
,
cdn
)
=>
(
{
filters
:
{
is_sales_item
:
1
}
}
)
)
;
→ See
references/methods.md
for complete method signatures.
Server Communication
frappe.call (Whitelisted Methods)
frappe
.
call
(
{
method
:
'myapp.api.process_data'
,
args
:
{
customer
:
frm
.
doc
.
customer
}
,
freeze
:
true
,
freeze_message
:
__
(
'Processing...'
)
,
callback
:
(
r
)
=>
{
if
(
r
.
message
)
{
frm
.
set_value
(
'result'
,
r
.
message
)
;
}
}
}
)
;
frm.call (Document Methods)
// Calls method on document controller
frm
.
call
(
'calculate_taxes'
,
{
include_shipping
:
true
}
)
.
then
(
r
=>
frm
.
reload_doc
(
)
)
;
Async/Await Pattern
async
function
fetchData
(
frm
)
{
let
r
=
await
frappe
.
call
(
{
method
:
'frappe.client.get_value'
,
args
:
{
doctype
:
'Customer'
,
filters
:
{
name
:
frm
.
doc
.
customer
}
,
fieldname
:
'credit_limit'
}
}
)
;
return
r
.
message
.
credit_limit
;
}
Child Table Handling
Adding Rows
let
row
=
frm
.
add_child
(
'items'
,
{
item_code
:
'ITEM-001'
,
qty
:
5
,
rate
:
100
}
)
;
frm
.
refresh_field
(
'items'
)
;
// REQUIRED after modification
Editing Rows
frm
.
doc
.
items
.
forEach
(
(
row
)
=>
{
if
(
row
.
qty
10 ) { row . discount_percentage = 5 ; } } ) ; frm . refresh_field ( 'items' ) ; Child Table Events frappe . ui . form . on ( 'Sales Invoice Item' , { qty ( frm , cdt , cdn ) { let row = frappe . get_doc ( cdt , cdn ) ; frappe . model . set_value ( cdt , cdn , 'amount' , row . qty * row . rate ) ; } , items_add ( frm , cdt , cdn ) { // New row added } , items_remove ( frm ) { // Row removed } } ) ; → See references/examples.md for complete child table examples. Custom Buttons frappe . ui . form . on ( 'Sales Order' , { refresh ( frm ) { if ( frm . doc . docstatus === 1 ) { // Grouped buttons frm . add_custom_button ( __ ( 'Invoice' ) , ( ) => { // action } , __ ( 'Create' ) ) ; // Primary action frm . page . set_primary_action ( __ ( 'Process' ) , ( ) => { frm . call ( 'process' ) . then ( ( ) => frm . reload_doc ( ) ) ; } ) ; } } } ) ; Critical Rules ALWAYS call frm.refresh_field('table') after child table modifications NEVER use frm.doc.field = value — use frm.set_value() ALWAYS use __('text') for translatable strings validate event: use frappe.throw() to prevent save setup event: only for one-time configuration (not repeated) → See references/anti-patterns.md for common mistakes.
erpnext-syntax-clientscripts
安装
npx skills add https://github.com/openaec-foundation/erpnext_anthropic_claude_development_skill_package --skill erpnext-syntax-clientscripts