How to make child table row read-only once status is active?

Hi,

I have a child table Drug Prescription inside the Patient Encounter doctype.
In this table, there is a field called medication_status with values like Booked, Dispensed, and Partially Dispensed.

:point_right: My requirement:

  • If medication_status is Dispensed or Partially Dispensed, that row should become read-only (i.e., user should not be able to edit the fields anymore).
  • If the status is Booked, the row should still be editable.

I tried overriding refresh and after_save with a function like this:

function disable_processed_rows(frm) {
    let rows = frm.fields_dict["drug_prescription"]?.grid?.grid_rows;
    if (!rows || !rows.length) return;

    rows.forEach(row => {
        let fields = ["medication", "dosage", "period", "dosage_form", "drug_code", "medication_status"];

        if (row.doc.medication_status === "Dispensed" || row.doc.medication_status === "Partially Dispensed") {
            fields.forEach(f => {
                if (row.columns[f] && row.columns[f].df) {
                    row.columns[f].df.read_only = 1;
                }
            });
        } else {
            fields.forEach(f => {
                if (row.columns[f] && row.columns[f].df) {
                    row.columns[f].df.read_only = 0;
                }
            });
        }
    });
}

The logic works partly, but the fields are still editable until I refresh the form.
Is there a proper way in Frappe to lock child table rows dynamically based on field value?

Any suggestions or best practices would be really helpful.

hi @RanganathanM , You can use read_only_depends_on for the child table fields. otherwise if you are using this code try adding frm.refresh_fields() after your loop

3 Likes

hi @RanganathanM use this frm.refresh_field(“drug_prescription”); after loop

1 Like

hi @Sajin_SR , @Jignesh_01

I tried implementing this with toggle_editable inside a child table, for example:

function toggle_child_fields(frm, cdt, cdn) {
    let row = locals[cdt][cdn];
    let grid_row = frm.fields_dict["drug_prescription"].grid.grid_rows_by_docname[cdn];

    if (!grid_row) return;

    if (row.quantity_required) {
        grid_row.toggle_editable("dosage_quantity", true);
    } else {
        grid_row.toggle_editable("dosage_quantity", false);
    }
}

The idea is:

  • If quantity_required checkbox is enabled → dosage_quantity becomes editable.
  • If quantity_required checkbox is disabled → dosage_quantity becomes read-only.

Drawback I observed
This works only for the active row. As soon as I switch to another row or add a new one, the field automatically becomes read-only again.

Is this the correct way of implementing such behaviour in child tables?

2 Likes

hide_n_show_child_table_fields(frm){
if (frm.doc.status == “Active”){
var dfy = frappe.meta.get_docfield(“Child Table Name”,“child_field”, frm.doc.name);
dfy.read_only = 1

    }
},

after_save: function(frm) {
frm.trigger(“hide_n_show_child_table_fields”);
},
like this you can freeze specific child table field as per the parent table fields