Dialog API
Frappe provides a group of standard, interactive and flexible dialogs that are easy to configure and use. There's also an API for Python.
frappe.ui.Dialog
new frappe.ui.Dialog({ title, fields, primary_action })
Creates a new Dialog instance.
let d = new frappe.ui.Dialog({
title: 'Enter details',
fields: [
{
label: 'First Name',
fieldname: 'first\_name',
fieldtype: 'Data'
},
{
label: 'Last Name',
fieldname: 'last\_name',
fieldtype: 'Data'
},
{
label: 'Age',
fieldname: 'age',
fieldtype: 'Int'
}
],
size: 'small', // small, large, extra-large
primary\_action\_label: 'Submit',
primary\_action(values) {
console.log(values);
d.hide();
}
});
d.show();
frappe.ui.Dialog
frappe.msgprint
frappe.msgprint(message)
or frappe.msgprint({ title, message, indicator })
Show message
in a modal.
// only message
frappe.msgprint(\_\_('Document updated successfully'));
// with options
frappe.msgprint({
title: \_\_('Notification'),
indicator: 'green',
message: \_\_('Document updated successfully')
});
frappe.msgprint
You can also bind a primary action to this dialog by passing action
(as a method) within primary_action
. Alternatively, primary_action
can contain server_action
or client_action
.
The server_action
and client_action
are dotted paths to the respective methods which will execute on clicking the primary button.
// with primary action
frappe.msgprint({
title: \_\_('Notification'),
message: \_\_('Are you sure you want to proceed?'),
primary\_action:{
action(values) {
console.log(values);
}
}
});
// with server and client action
frappe.msgprint({
title: \_\_('Notification'),
message: \_\_('Are you sure you want to proceed?'),
primary\_action: {
'label': 'Proceed',
// either one of the actions can be passed
'server\_action': 'dotted.path.to.method',
'client\_action': 'dotted\_path.to\_method',
'args': args
}
});
frappe.msgprint with primary action bound
frappe.throw
frappe.throw(error_message)
Show error_message
in a modal and throw
exception.
frappe.throw(__('This is an Error Message'))
frappe.throw
frappe.prompt
frappe.prompt(label)
or frappe.prompt(df)
or frappe.prompt(fields)
Prompt user for a value or list of values.
// prompt for single value of type Data
frappe.prompt('First Name', ({ value }) => console.log(value))
// Set title and button label
frappe.prompt('First Name', console.log, 'Enter First Name', 'Submit');
// prompt for single value of any type
frappe.prompt({
label: 'Birth Date',
fieldname: 'date',
fieldtype: 'Date'
}, (values) => {
console.log(values.date);
})
// prompt for multiple values
frappe.prompt([
{
label: 'First Name',
fieldname: 'first\_name',
fieldtype: 'Data'
},
{
label: 'Last Name',
fieldname: 'last\_name',
fieldtype: 'Data'
},
], (values) => {
console.log(values.first\_name, values.last\_name);
})
frappe.prompt
frappe.confirm
frappe.confirm(message, if_yes, if_no)
Show a confirmation modal, executes if_yes
if confirmation is given else executes if_no
.
frappe.confirm('Are you sure you want to proceed?',
() => {
// action to perform if Yes is selected
}, () => {
// action to perform if No is selected
})
frappe.confirm
frappe.warn
frappe.warn(title, message_html, proceed_action, primary_label, is_minimizable)
Show a warning modal, executes proceed_actiion
if confirmation is given. It can be set as minimizable
which allows the dialog to be minimized.
frappe.warn('Are you sure you want to proceed?',
'There are unsaved changes on this page',
() => {
// action to perform if Continue is selected
},
'Continue',
true // Sets dialog as minimizable
)
frappe.confirm
frappe.show_alert
frappe.show_alert(message, seconds)
or frappe.show_alert({message, indicator}, seconds)
Alert Dialog is used for showing non-obstructive messages.
Its parameters include message
, which can contain the indicator color as well, and its display duration. The default is 7 seconds.
frappe.show\_alert('Hi, you have a new message', 5);
//show\_alert with indicator
frappe.show\_alert({
message:\_\_('Hi, you have a new message'),
indicator:'green'
}, 5);
frappe.show_alert
frappe.show_progress
frappe.show_progress(title, count, total, description)
Displays a progress bar with count
(as current progress) and total
(as maximum progress value).
frappe.show\_progress('Loading..', 70, 100, 'Please wait');
frappe.show_progress
frappe.new_doc
frappe.new_doc(doctype, route_options, init_callback)
Opens a new form of the specified DocType that allows to edit and save it. If "Quick Entry" is enabled for the DocType (that allows to enter the most important fields) the "Quick Entry" pop-up window will be shown. Otherwise you will be redirected to the usual document entry form.
For example, let's create a new Task:
frappe.new\_doc("Task");
Often when you are creating a new document in the user interface you want to initialize some of its fields based on the user interaction that triggered the creation. The other two arguments can be used for such initialization.
Specifically, the route_options
argument is a quick and convenient way to set any field of type Link, Select, Data, or Dynamic Link in the new document. Its value should be an object whose keys are the desired field names and whose values are the initial values.
frappe.new\_doc("Task", {subject: "New Task"});
If you need to do any other initialization of the new document that is not possible with route_options
, init_callback
gives you full control. It should be a function of one argument. If the doctype is initialized with a "Quick Entry" form, the callback is called with the "Quick Entry" dialog object just before control is released back to the user. Otherwise, the callback is called with the new document just before the user is allowed to edit it in the standard form.
frappe.new_doc("Task", {subject: "New Task"},
doc => {doc.description = "Do what's necessary";});
Note that subject
is a field of type "Data", so we are able to take advantage of the route_options
argument to set it. description
is a field of type "Text Editor", so if we want to initialize it, that must be done in the callback.
For a slightly more complex example, here's a call that creates a new Journal Entry of type "Bank Entry" and populates one side of the transaction:
frappe.new_doc("Journal Entry", {"voucher_type": "Bank Entry"}, doc => {
doc.posting\_date = frappe.datetime.get_today();
let row = frappe.model.add_child(doc, "accounts");
row.account = 'Bank - A';
row.account\_currency = 'USD';
row.debit\_in\_account\_currency = 100.0;
row.credit\_in\_account\_currency = 0.0;
});
frappe.ui.form.MultiSelectDialog
new frappe.ui.form.MultiSelectDialog({ doctype, target, setters, date_field, get_query, action })
A MultiSelectDialog consists of filter fields followed by a multiple selection list. The primary button will perform the passed action
on the selected options.
By default, the Search Term field and Date Range field will compose the filter fields.
The argument list includes:
doctype
: The source to fetch and display selection entries from.target
: The target where the modal is to be displayed.setters
: These will compose the filter fields and values to populate them with. These also translate to custom columns for the selection list.read_only_setters
: If you want to make setters (filters) read only so that users can't change the value of the filters then add those fields in the "readonlysetters".add_filters_group
: A boolean value to add/remove the filter group in the dialog belowsetters
. The filter group is same as the list view filters.date_field
: It is necessary to pass thedate_field
of the DocType in consideration.get_query
: A function that returnsquery
andfilters
to query the selection list. A custom server side method can be passed viaquery
, andfilters
will be passed to that method.action
: Contains the primary action to be performed on the selected options. It takesselections
as a parameter, which comprises of the selected options.columns
: An array of fields returned by custom query which will become columns in result datatable. Only works with the custom query (get_query
argument returning aquery
).
Let us assume we want to fetch Material Requests into our dialog. We can then go on to invoke the MultiSelectDialog in the following manner:
new frappe.ui.form.MultiSelectDialog({
doctype: "Material Request",
target: this.cur_frm,
setters: {
schedule\_date: null,
status: 'Pending'
},
add\_filters\_group: 1,
date\_field: "transaction\_date",
get\_query() {
return {
filters: { docstatus: ['!=', 2] }
}
},
action(selections) {
console.log(selections);
}
});
// MultiSelectDialog with custom query method
let query_args = {
query:"dotted.path.to.method",
filters: { docstatus: ["!=", 2], supplier: "John Doe" }
}
new frappe.ui.form.MultiSelectDialog({
doctype: "Material Request",
target: this.cur_frm,
setters: {
schedule\_date: null,
status: 'Pending'
},
add\_filters\_group: 1,
date\_field: "transaction\_date",
columns: ["name", "transaction\_date", "status"],
get\_query() {
return query_args;
},
action(selections) {
console.log(selections);
}
});
frappe.ui.form.MultiSelectDialog
Here all the Material Requests that fulfill the filter criteria will be fetched into the selection area. The setter company
is added to the filter fields along with its passed value. The date_field
will be used to fetch and query dates from the DocType mentioned.
The Make Material Request (or Make {DocType}
) secondary action button will redirect you to a new form in order to make a new entry into the DocType passed.
Now, if we want to only select particular item from a Material Request, then we can use optional child_selection_mode
to enable child selection
// MultiSelectDialog for individual child selection
new frappe.ui.form.MultiSelectDialog({
doctype: "Material Request",
target: this.cur_frm,
setters: {
schedule\_date: null,
status: null
},
add\_filters\_group: 1,
date\_field: "transaction\_date",
allow\_child\_item\_selection: 1,
child\_fieldname: "items", // child table fieldname, whose records will be shown & can be filtered
child\_columns: ["item\_code", "qty"], // child item columns to be displayed
get\_query() {
return {
filters: { docstatus: ['!=', 2] }
}
},
action(selections, args) {
console.log(args.filtered_children); // list of selected item names
}
});
frappe.ui.form.MultiSelectDialog
Here you will see a checkbox Select Individual Items to toggle between child item selection & parent selection. Once you toggle it, all the individual Material Requests Items are listed from the all the queried Material Request, you can now filter these items for selection.
To access the selected children, you can use args.filtered_children
list which contains selected child item names.
Table / Grid in a Dialog
A table can be added to a dialog, just like any other field as follows:
const dialog = new frappe.ui.Dialog({
title: \_\_("Create Logs"),
fields: [
{
fieldname: "logs",
fieldtype: "Table",
label: \_\_("Logs"),
in\_place\_edit: true,
reqd: 1,
fields: [
{
fieldname: "log\_type",
label: \_\_("Log Type"),
fieldtype: "Select",
options: "\nIN\nOUT",
in\_list\_view: 1,
reqd: 1,
},
{
fieldname: "time",
label: \_\_("Time"),
fieldtype: "Time",
in\_list\_view: 1,
reqd: 1,
}
],
on\_add\_row: (idx) => {
// idx = visible idx of the row starting from 1
// eg. set `log\_type` as alternating IN/OUT in the table on row addition
let data_id = idx - 1;
let logs = dialog.fields_dict.logs;
let log_type = (data_id % 2) == 0 ? "IN" : "OUT";
logs.df.data[data_id].log_type = log_type;
logs.grid.refresh();
},
},
],
primary_action: (values) => { ... },
primary_action_label: \_\_("Create"),
});
on_add_row
: An event that gets triggered on adding a row to the table. You can perform an action like data manipulation or some other sort of calculation by adding your functionality to this event hook.