How to Make a Field Read-Only Dynamically in Frappe ERPNext
Make Read only fieldLearn to dynamically set field properties like read-only, required, or options in ERPNext and Frappe using Client Scripts with cur_frm.set_df_property.
In Frappe and ERPNext, creating a dynamic and responsive user interface is key to building effective applications. One common requirement is to change a field's properties based on user input or document state, such as making a field read-only after a document is submitted or based on the value of another field. This can be easily achieved using Frappe's Client Script API.
This guide explores the two primary methods for controlling field properties on the client-side: the standard `cur_frm.set_df_property` function and the more direct `frappe.meta.get_docfield` method. We'll cover how to make fields read-only, required, and even how to update options for select fields.
1 // Method 1: Using cur_frm.set_df_property (Recommended) 2
3 // Make a field read-only 4 cur_frm.set_df_property("net_weight", "read_only", 1); 5
6 // Make a field required based on a condition 7 cur_frm.set_df_property("cheque_no", "reqd", doc.voucher_type == "Bank Entry"); 8
9 // General Syntax: cur_frm.set_df_property(FIELDNAME, PROPERTY, VALUE); 10
11
12 // Method 2: Directly manipulating the docfield object 13
14 var df = frappe.meta.get_docfield("Sales Invoice", "customer_name", cur_frm.doc.name); 15 if (df) { 16 df.read_only = 1; 17 cur_frm.refresh_field("customer_name"); // UI refresh is needed 18 } 19
20 // Example: Dynamically setting options for a Select field in a child table 21 var child_df = frappe.meta.get_docfield("Employer Project Details", "company_name", cur_frm.doc.name); 22 if(child_df) { 23 child_df.options = ["Tech M", "Wipro", "TCS"]; 24 cur_frm.refresh_field("employer_project_details"); // Refresh the whole child table field 25 }
Understanding This Code
What It Does
This snippet demonstrates how to programmatically change a field's properties, such as making it read-only, required, or updating its options, directly from a Frappe Client Script.
When To Use
Use this in Client Script triggers like `onload`, `refresh`, or on a field's `onchange` event to create a responsive and context-aware user interface in any DocType form.
Prerequisites
- •Basic understanding of Frappe DocTypes
- •Familiarity with creating Client Scripts in Frappe.
Key Concepts
Important ideas to understand in this code
cur_frm
A global object in Frappe Client Scripts that represents the current form being viewed. It provides access to the document's data (`cur_frm.doc`), metadata, and a rich API for form manipulations.
Learn morecur_frm.set_df_property
The standard API function to change a property of a DocField. It takes three arguments: the fieldname, the property to change (e.g., 'read_only', 'reqd', 'hidden', 'options'), and the new value. This method automatically handles UI refreshes.
Learn morefrappe.meta.get_docfield
A lower-level function that retrieves the complete DocField object for a given field. This is useful for more complex manipulations but requires a manual UI refresh using `cur_frm.refresh_field()` after modification.
Learn moreClient Script Events
These are JavaScript triggers that execute code at specific points in the form lifecycle. Common events include `onload` (when the form loads), `refresh` (after data is saved/refreshed), and `field_name_onchange` (when a specific field's value changes).
Learn moreStep-by-Step Tutorial
Follow along to understand how this code works
Identify the DocType and Fields
First, determine which DocType you want to modify. For this example, we'll use the 'Sales Order' DocType. We want to make the 'delivery_date' field read-only if the 'status' is 'Delivered'.
// DocType: Sales Order
// Trigger Field: status
// Target Field: delivery_dateCreate a New Client Script
Navigate to 'Client Script' from the Awesome Bar. Click 'Add Client Script', and select 'Sales Order' for the 'DocType'.
// In ERPNext Desk:
// Go to > Client Script List > Add Client Script
// Select DocType: Sales OrderWrite the Script Logic
We'll use the `refresh` event handler. This code will run every time the form is loaded or refreshed. It checks the document's status and sets the 'read_only' property accordingly.
frappe.ui.form.on('Sales Order', {
refresh: function(frm) {
// Set a variable for the condition to make it cleaner
var is_delivered = frm.doc.status === 'Delivered';
// Set the 'delivery_date' field's read_only property
frm.set_df_property('delivery_date', 'read_only', is_delivered);
}
});Save and Test
Save the Client Script and ensure it is enabled. Now, navigate to any 'Sales Order' document. If the status is 'Delivered', the 'Delivery Date' field will be non-editable. If you change the status to something else and save, the field will become editable again upon refresh.
// 1. Save the Client Script.
// 2. Make sure the 'Enabled' checkbox is checked.
// 3. Go to a Sales Order form and reload the page.
// 4. Observe the 'delivery_date' field's state based on the 'status'.Common Issues & Solutions
Troubleshoot problems you might encounter