When customizing forms in Frappe / ERPNext, one of the most common UI requirements is:
Filter a Link field inside a child table based on another field from the same child-table row.
For example:
Inside a child table row, a user selects a Item Group, and the next field Item should show only items belonging to that selected Item Group — but only for that row.
This improves data accuracy and makes the form more intelligent.
In this blog, we’ll cover exactly how to implement this using frm.set_query() with proper usage of cdt and cdn.
🔍 Understanding the Scenario
Let’s assume your child table has fields:
| Fieldname | Label | Type |
|---|---|---|
| item_group | Item Group | Link (Item Group) |
| item | Item | Link (Item) |
Goal:
When the user selects category in a row, the item field dropdown should show only items under that category — but only for that specific row.
This is done using dynamic filtering inside the child table.
✅ Correct Script: Filtering Child Table Field Based on Another Field in Same Row
frappe.ui.form.on("Parent Doctype", {
setup(frm) {
frm.set_query("item(child_table_field_to_filter)", "items(child_table_field_name)", function (doc, cdt, cdn) {
let row = frappe.get_doc(cdt, cdn);
return {
filters: {
item_group: row.item_group
}
};
});
},
});
✔ What this script does:
• "item" → the field to filter
• "items" → child table fieldname
• row = frappe.get_doc(cdt, cdn) → fetches the current child row
• row.item_group → gets the user-selected item group in the same row
• Filters the Item dropdown based on this category
This ensures each row behaves independently.
🧠 How It Works (Simplified)
- User selects a Category in that row
- ERPNext triggers the query for the Item field
- The script fetches the same row data
- Link field shows only filtered items
This is row-level filtering, not table-level.
🧪 Example Use Case
A manufacturing BOM child table:
- Select Raw Material Type
- Show only materials of that type in Material field
- Avoids wrong selections
- Reduces validation errors
- Makes user experience cleaner
This is widely used in:
- Textile weaving Bill of Materials
- Diamond planning & assorting
- Inventory classification
- Manufacturing inputs selection
⚠ Common Mistakes to Avoid
❌ Using frm.doc.items[row.idx]
This fails because indexing changes when rows are reordered.
❌ Using refresh
Filtering should be inside setup, not refresh.
❌ Applying query at parent level without cdt and cdn
This won’t work for child-table dynamic values.
🏁 Final Thoughts
Filtering a child-table Link field based on another field in the same row is one of the most powerful customisations in Frappe. With only a few lines of code, you create a dynamic, intelligent child table that reduces user mistakes and improves data quality.
This technique is essential for anyone building ERPNext custom apps, scripts, or advanced forms — especially in manufacturing and inventory workflows.
