Loading...
Loading...
Exact JavaScript syntax for ERPNext/Frappe Client Scripts. Use when writing client-side code for form events, field manipulation, server calls, or child table handling in ERPNext v14/v15/v16. Triggers: client script, form event, frm methods, frappe.call, frappe.ui.form.on, JavaScript in ERPNext, browser-side code, UI interaction, client-side field validation.
npx skill4agent add openaec-foundation/erpnext_anthropic_claude_development_skill_package erpnext-syntax-clientscriptspublic/js/frappe.ui.form.on('DocType Name', {
// Form-level events
setup(frm) { },
refresh(frm) { },
validate(frm) { },
// Field change events
fieldname(frm) { }
});| Action | Code |
|---|---|
| Set value | |
| Hide field | |
| Make field mandatory | |
| Call server | |
| Prevent save | |
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}// 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;// 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);// 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 }
}));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);
}
}
});// Calls method on document controller
frm.call('calculate_taxes', { include_shipping: true })
.then(r => frm.reload_doc());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;
}let row = frm.add_child('items', {
item_code: 'ITEM-001',
qty: 5,
rate: 100
});
frm.refresh_field('items'); // REQUIRED after modificationfrm.doc.items.forEach((row) => {
if (row.qty > 10) {
row.discount_percentage = 5;
}
});
frm.refresh_field('items');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
}
});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());
});
}
}
});frm.refresh_field('table')frm.doc.field = valuefrm.set_value()__('text')frappe.throw()erpnext-impl-clientscriptserpnext-errors-clientscriptserpnext-syntax-whitelisted