[Tutorial] set_df_property | Parent Table & Child Table | 2023

New Project (1)

Summary

Learn how to use the set_df_property function in ERPNext to dynamically modify properties of DocField (fields) in your custom applications. This powerful feature allows you to customize field behavior, such as making fields read-only, hiding them conditionally, or setting default values. Enhance your ERPNext application with this tutorial!

Reference Documentation

Get Started

Syntax

frm.set_df_property(fieldname, property, value, docname, table_field, table_row_name)

fieldname - Parent Doctype Field Name
property - read_only, reqd, hidden …etc
value - 1 or 0 or characters
docname - Name of the current doctype | frm.docname
table_field - Field Inside the child table
table_row_name - name of the row | child.name

Parent Doctype

I’m creating a parent doctype with the name of School you can use custom doctype or core doctype

Child Table

Student List

Lets Explore

Parent

I hope you all get some ideas going to change the school_name field as Mandatory

frm.set_df_property('school_name', 'read_only', 1)

This a sample example for parent doctype its applicable to any fields in parent doctype

Child Table
Change the roll_no as Mandatory

frm.set_df_property('students', 'reqd', 1, frm.docname, 'roll_no', child.name)

How to add these feature in school.js

school.js

// Parent Doctype
frappe.ui.form.on('School', {
   refresh: function(frm){
   frm.set_df_property('school_name', 'read_only', 1)
   }
});

// Child Table
frappe.ui.form.on('Student List', { 
   students_add: function(frm, cdt, cdn){
     var child = locals[cdt][cdn]
     frm.set_df_property('students', 'reqd', 1, frm.docname, 'roll_no', child.name)
   }
})

You can change and play with this single syntax in any of your fields property

List of property

There is lot of options is there i listed some of them frequently used.

Property Value Description
read_only 1 or 0 Make the field as read only
reqd 1 or 0 Make the field as Mandatory
bold 1 or 0 Make the field as bold
hidden 1 or 0 Make the field as Hidden
options List of Values or link Doctype Can Link Any Doctype Dynamicaly if its a select field we can change the options
default Any Value Set Default value for the field

Please Support with you likes and comments

Github: Antony-M1 · GitHub
Linkedin: Antony

18 Likes

I have tried it but no success I wanted to set uom link field in purchase invoice item to the one set in item uoms table , so I have created server script of type api which response with list of uom for that item and call it get_uoms,

/ Parent Doctype
frappe.ui.form.on('Purchase Invoice', {
   refresh: function(frm){
   
   }
});

// Child Table
frappe.ui.form.on('Purchase Invoice Item', { 
   item_code: function(frm, cdt, cdn){
     var child = locals[cdt][cdn];
frappe.call("get_uoms", {message:child.item_code}).then(r=<
     frm.set_df_property('students', 'reqd', 1, frm.docname, 'roll_no', child.name)
   }
})

You can change and play

This tutorial assumes your access to Child Table fields is obtained through:

var child = locals[cdt][cdn]

If you are coding in the parent DocType context (refresh(), setup(), after_save(), onload(), etc) you cannot use that to get at fields in the child table.

Elsewhere in this forum you will find explanations of how to set_df_property for a specific field in all child table rows at once.

In my case I am :

  • coding in the parent DocType context
  • setting single fields in specific rows to read_only

I have found these are all viable ways to get at a specific field in a specific row …

	    let student;
	    let aRow = 22;

	    student = frm.fields_dict['students'].grid.grid_rows[aRow].doc;
	    console.dir(student);
	    frm.set_df_property('students', 'read_only', 1, frm.docname, 'roll_no', student.name)

	    student = frm.get_field("students").grid.data[aRow];
	    console.dir(student);
	    frm.set_df_property('students', 'read_only', 1, frm.docname, 'roll_no', student.name)

        student = frm.doc.students[aRow];
	    console.dir(student);
	    frm.set_df_property('students', 'read_only', 1, frm.docname, 'roll_no', student.name)

4 Likes

Thanks For Your Contribution. its really great

1 Like

Can we set these properties using python?

No you should use in the Js file

Goated tutorial, this should be in the official documentation. Please Frappe devs add this, this is such an important concept, that should be accessible to everyone without searching google for this forum post.

2 Likes

Hi,

I am using this same function on filtering the data from another doctype as below

// scripting to automate fetching or populating these fields based on user input
frappe.ui.form.on(‘Sample’, {
branch_type: function(frm) {
// frappe.msgprint(__(‘Invalid value for field: field_name’));
frappe.call({
method: “frappe.client.get_list”,
args: {
doctype: “branchtype”,
filters: {
branch_type: frm.doc.branch_type
},
fields: [“zone”]
},
callback: function(r) {
var zone_options = r.message.map(function(d) { return d.zone; });
frm.set_df_property(‘zone’, ‘options’, zone_options.join(‘\n’));
console.log(zone_options);
}
});
}
});

I successfully able to filter the data and able to select the data but the issue is once it gets saved the data not getting appeared in the field but the list showing the data which i have selected and saved.

Is there any solution…
List showing the value saved in the field

but the doctype contains nothing

please help!!!

Try the functionality in the refresh event

frappe.ui.form.on(‘Sample’, {
  refresh: function(frm) {
    // frappe.msgprint(__(‘Invalid value for field: field_name’));
    if Boolean(frm.doc.branch_type){
         frappe.call({
          method: “frappe.client.get_list”,
          args: {
          doctype: “branchtype”,
          filters: {
            branch_type: frm.doc.branch_type
            },
      fields: [“zone”]
      },
      callback: function(r) {
        var zone_options = r.message.map(function(d) { return d.zone; });
        frm.set_df_property(‘zone’, ‘options’, zone_options.join(‘\n’));
        console.log(zone_options);
      }
      });
    }
    
  }
});
2 Likes

Thks it is working now

1 Like

How to set Description on selection of Field?
I tried below script but its not working.

frappe.ui.form.on('Travel Request', {
	date_of_birth: function(frm) {
            // working
	    frm.set_df_property('date_of_birth', 'description', 'Text Hello');
	}
})

frappe.ui.form.on('Travel Itinerary', {
	custom_departure_time: function(frm, cdt, cdn) {
	    var row = locals[cdt][cdn];
	    console.log(row.name)
	    console.log(frm.docname)
            // not working
	    frm.set_df_property('itinerary', 'description', "test text", frm.docname, 'custom_departure_time', row.name);
	}
})

I want to show some text when time is selected in Field (Type Time).

Please suggest what i am doing wrong?

Solved.
Thanks @Antony_Praveenkumar

frappe.ui.form.on('Travel Itinerary', {
	custom_departure_time: function(frm, cdt, cdn) {
	    let row = locals[cdt][cdn];
	    let message = "Confirm!"
	    frm.set_df_property('itinerary', 'description', message, frm.doc.name, 'custom_departure_time', row.name);
	    frm.refresh_field('itinerary');
	}
})
1 Like

Hi,

Need your advise on below scenario I am trying to create a list in the child table to perform the selection based on the field populated by the user.

I am trying to target the list which filtered through the frappe call and produce the options.
I want to store the list in the field for the selection

Pls advise.

frappe.ui.form.on('Stationery Item Info_new', {
item_information_add(frm, cdt, cdn) {
    var child = locals[cdt][cdn];
    child.product_line = frm.doc.product_line;
    child.sub_category = frm.doc.product_line;
    
    frappe.call({
        method: "frappe.client.get_list",
        args: {
          doctype: "Stationery Product Category",
          filters: {
            product_line: frm.doc.product_line,
          },
          fields: ["category"],
        },
        callback: function (r) {
            let data = r.message;
            if (data && data.length > 0) {
                var category_options = r.message.map(function (d) {
                    return d.category;
                });
//this is working but it gets populated once revisit the site
            var df = frappe.meta.get_docfield("Stationery Item Info_new","category", cur_frm.doc.name);
            df.options = category_options.join("\n");
// below code not working at all
	    frm.set_df_property('item_information', 'options', category_options, frm.doc.name, 'category', row.name);
	    frm.refresh_field('item_information');
            }
            
        }
        
    });
    }
});

Hello,

I want to update Description of Field in Child Table every time field value is selected or changed.

For that I have written below Client Script which is working but It’s updating Description only first time when I selects value in field.

frappe.ui.form.on('Child Table Name', {
	child_table_field_name: function(frm, cdt, cdn) {
	    let row = locals[cdt][cdn];
	    let x = Math.random();
	    frm.set_df_property('child_table_name', 'description', x, frm.docname, 'child_table_field_name', row.name);
        frm.refresh_field("child_table_name");
	}
});

Actual Script

frappe.ui.form.on('Travel Itinerary', {
	custom_departure_time: function(frm, cdt, cdn) {
	    let row = locals[cdt][cdn];
	    let x = Math.random();
	    console.log(x);
	    frm.set_df_property('itinerary', 'description', x, frm.docname, 'custom_departure_time', row.name);
        frm.refresh_field("itinerary");
	}
});

Before Selecting Vales.

After Value Selected Multiple Times, Description changed first then remains same.

Any suggestions please.

Thanks.

How to set list of values in child table select field which produced through filtering using frappe call… I able to filter but value not getting populated as list… Please guide…

Please ensure the setting values after you getting data from the frappe.call. please use async=false in the frappe.call. ensure you are setting correct field. make sure that field is a Select field.

Hi Antony Thanks for the reply. I am trying to achieve as below

  1. If the user update the Product Line then click add the child table need to provide the option of the values in the Category Field for the user to perform the selection.

  2. Based on the selection Item name also need to be listed for the selection.

frappe.ui.form.on('Stationery Item Info_new', {
item_information_add(frm, cdt, cdn) {
    var child = locals[cdt][cdn];
    child.product_line = frm.doc.product_line;
    child.sub_category = frm.doc.product_line;
    
    frappe.call({
        method: "frappe.client.get_list",
        args: {
          doctype: "Stationery Product Category",
          filters: {
            product_line: frm.doc.product_line,
          },
          fields: ["category"],
        },
        callback: function (r) {
            let data = r.message;
            if (data && data.length > 0) {
                var category_options = r.message.map(function (d) {
                    return d.category;
                });
                console.log(category_options);
	    frm.set_df_property('item_information', 'options', category_options, frm.doc.name, 'category', row.name);
	    frm.refresh_field('item_information');
            }
            
        }
        
    });
    }
});

Here is the code seems there is no issue on retrieving the data but setting the value and refresh not happening.

please advise.