Frappe Client Scriptjavascript

How to Create a Mapped Document from a Custom Button in Frappe

Map Document using custom button

Learn how to add a custom button to a Frappe form that triggers the creation of a new, mapped document using the 'frappe.model.open_mapped_doc' method in a Client Script.

This guide demonstrates how to create a custom button on a Frappe form that, when clicked, initiates the creation of a new document by mapping data from the current form. This is a common requirement for streamlining workflows, such as creating a 'Meeting' from a 'Meeting Schedule'.

The solution involves using a Client Script to hook into the form's `refresh` event, adding the button, and then calling the `frappe.model.open_mapped_doc` utility function. This function calls a whitelisted Python server method to handle the data mapping and document creation logic.

javascript
1frappe.ui.form.on('Meeting Schedule', {
2 refresh: function(frm) {
3 frm.add_custom_button(__("Create Meeting"), function() {
4 frappe.model.open_mapped_doc({
5 method : "eie.eie.doctype.meeting_schedule.meeting_schedule.make_meeting",
6 frm : cur_frm
7 })
8 })
9 }
10});

Understanding This Code

What It Does

Adds a custom button named 'Create Meeting' to the 'Meeting Schedule' form. Clicking this button triggers a server-side Python method to create a new, mapped 'Meeting' document.

When To Use

Use this approach when you need to provide users with a one-click action to create a related document from an existing one, pre-filling data based on defined mapping rules.

Key Concepts

Important ideas to understand in this code

Form Event Triggers

The 'frappe.ui.form.on' method is a client-side API used to attach event handlers to DocType forms. The 'refresh' event is triggered every time the form is loaded or reloaded, making it the ideal place to add custom buttons or modify form behavior.

Learn more

Adding Custom Buttons

This Form object method, 'frm.add_custom_button', allows developers to dynamically add buttons to the form's header. It takes the button label and a callback function to be executed when the button is clicked.

Learn more

Creating Mapped Documents

A powerful utility that streamlines the creation of a new document from an existing one. It calls a specified server-side (Python) method, passing the current form's context. The server method is responsible for creating the new document and returning its details, after which the client is redirected to the new document's form.

Learn more

Step-by-Step Tutorial

Follow along to understand how this code works

1

Create a New Client Script

First, navigate to the 'Client Script' list in your Frappe desk. Create a new script and select 'Meeting Schedule' as the DocType to which it applies.

bash
// No code for this step. This is a UI action.
Next Step
2

Hook into the Refresh Event

Use the 'frappe.ui.form.on' method to specify that your code should run every time the 'Meeting Schedule' form is refreshed.

javascript
frappe.ui.form.on('Meeting Schedule', {
	refresh: function(frm) {
		// Your button logic will go here
	}
});
Next Step
3

Add the Custom Button

Inside the 'refresh' function, call 'frm.add_custom_button'. The first argument is the button's label, and the second is the function that will execute when the button is clicked.

javascript
frm.add_custom_button(__("Create Meeting"), function() {
	// The action to perform on click goes here
});
Next Step
4

Call 'open_mapped_doc'

In the button's click handler, call 'frappe.model.open_mapped_doc'. This function requires an object specifying the whitelisted Python 'method' to call and the current form 'frm' to pass as context.

javascript
frappe.model.open_mapped_doc({
	method : "eie.eie.doctype.meeting_schedule.meeting_schedule.make_meeting",
	frm : cur_frm
})
Next Step
5

Implement the Server-Side Python Method

The 'method' specified points to a Python function. You must create this function in the specified path (e.g., 'meeting_schedule.py') and whitelist it with '@frappe.whitelist()' for it to be callable from the client-side.

python
import frappe
from frappe.model.mapper import get_mapped_doc

@frappe.whitelist()
def make_meeting(source_name, method='post'):
	doc = get_mapped_doc('Meeting Schedule', source_name, {
		'Meeting Schedule': {
			'doctype': 'Meeting',
			'field_map': {
				'name': 'meeting_schedule',
				# map other fields here, e.g., 'subject': 'subject'
			}
		}
	})
	doc.insert()
	return doc

Common Issues & Solutions

Troubleshoot problems you might encounter