How to add custom button to the list page of custom doctype

Hello everyone
I am trying to add a custom button on the custom_doctype_list.js
such that when I click the button it will trigger a function which might import entries in the list or delete entries in the list page

I read that its not supported in the older version so do we have any solution of such a usecase where I want to perform actions on the list of any doctype

Thank you
@NCP @kid1194 @iMoshi @Ulter52 @brian_pond
(I have tagged some of you cause I have found that you guys have helped people in similar issues)

There are two ways you can achieve this.
One through custom script and another through customization

  1. through Custom script(aka client script). The below example is to call a report from BOM Screen

frappe.ui.form.on('BOM', {

	refresh(frm) {
	    //Add the "Report" button in BOM 
	    frm.add_custom_button(__("Report"), function() {
        // When this button is clicked,

        var subject = frm.doc.subject;
        var event_type = frm.doc.event_type;

        // Call the BOM Analysis Report with filter of BOM field set to current BOM
        frappe.set_route('query-report', 'BOM Analysis', {"BOM": frm.doc.name});
    });

	}
});
  1. Using Customize Option

@gsarunk The code that you gave is for the Custom doctype, right?
What I want is to add a button on the List page (eg. contact list, customer list,etc )

Like if you see there are some [doctype]_list.js files availableā€¦I want to add my code there

@Harsh_Magiya You can either create a Client Script for each doctype list you want or you can create a custom plugin that checks of the current route matches any of the desired lists of doctypes and the add the buttonā€¦

Note: The plugin js script will run on every page thus the current route check is to limit the execution of the whole code in unwanted pagesā€¦

Letā€™s assume the name of the DocType is ā€œCustomerā€. So the name of the related JS file is 'customer_list.js'

Below is an example of adding a button to the List Page.


frappe.listview_settings['Customer'] = {

    onload: function (listview) {

        // Add a button for doing something useful.
        listview.page.add_inner_button(__("Name of My Button"), function () {
            some_js_function(listview);  // change to your function's name
        })
        .addClass("btn-warning").css({'color':'darkred','font-weight': 'normal'});
        // The .addClass above is optional.  It just adds styles to the button.
    }
};
3 Likes

To add a button to List view try this method highlighted in the post

Hello
Thank you so much @brian_pond @kid1194 @gsarunk
I will try out these methods today and will update you if all of them works

Hello @brian_pond
Can you confirm if this is correct :
Cause it is not giving any response, So how can I add a function for the button
doctype_list.js

frappe.listview_settings['doctype'] = {

    onload: function (listview) {

        // Add a button for doing something useful.
        listview.page.add_inner_button(__("Button"), function () {
                        frappe.call({
                                doc: frm.doc,
                                method: 'print_msg',
                                freeze: true,
                                callback: function() {
                                        frm.reload_doc();
                                }
                        });  // change to your function's name
        })
//        .addClass("btn-warning").css({'color':'darkred','font-weight': 'normal'});
        // The .addClass above is optional.  It just adds styles to the button.
    }
};

doctype.py

@frappe.whitelist()
        def print_msg(self):
                frappe.msgprint(('Success'))

Hey @brian_pond
Can you guide me here

Your doctype name is Doctype?
The name of the doctype should be in Capital.

I edit your post for better readability.
Maybe next time you can use ``` (triple backtick) for code.

1 Like

Hey its in capital only
I edited that just for simplicity

This is the code

frappe.listview_settings['Template'] = {

    onload: function (listview) {

        // Add a button for doing something useful.
        listview.page.add_inner_button(__("Button"), function () {
                        frappe.call({
                                doc: frm.doc,
                                method: 'print_msg',
                                freeze: true,
                                callback: function() {
                                        frm.reload_doc();
                                }
                        });  // change to your function's name
        })
//        .addClass("btn-warning").css({'color':'darkred','font-weight': 'normal'});
        // The .addClass above is optional.  It just adds styles to the button.
    }
};

The method must be in dotted path from your app to the function in py file.

Hey @rahy Sorry I did not get that
Can you show an example or something
Thank you

for example:

method: ā€˜yourcustomapp.yourdoctype.yourfunctionfile.yourfunctionā€™

Heyy rahy
So i tried this method
I also tried this custom_app.custom_module.doctype.custom_doctype.functionfile.function_name
So bith of them showed no action

@Harsh_Magiya There is no action because frm.doc doesnā€™t exist in listview_settingsā€¦

So if you want it to work, you should:

  1. Put the method outside the doctype class in python. Just put the method at the end of the python file and donā€™t add any indent before def, just like the code bellow.
class DoctypeName(Document):
    def...
    ...

@frappe.whitelist()
def print_msg():
    frappe.msgprint(('Success'))
  1. Remove the doc argument in the frappe.call and donā€™t use frm.reload_doc since there is not frm in list view. Follow the code bellow.
frappe.call({
    method: 'custom_app.custom_module.doctype.custom_doctype.doctype_file_name.print_msg',
    // Use args property to pass data to the python method
    // Python method: def print_msg(name, age):
    args: {name: 'some_name', age: 30},
    callback: function(ret) {
        // If you expect something to return form the call use the code bellow or replace it with your own code
        if (!ret || ret.message == null) return;
        let data = ret.message;
        
    }
});
1 Like

Hey just a correction if you can remove the self from print_msg() in python file
Thank you this worked
And just a last doubt
can you explain this conditions you wrote

if (!ret || ret.message == null) return;
        let data = ret.message;
1 Like

@Harsh_Magiya Iā€™m glad to hear that it worked for youā€¦

And thanks for pointing out my mistake. I have fixed the python codeā€¦

Letā€™s say that in the print_msg python method you returned a string, like return "This is a test",
then in the JavaScript code, callback: function(ret) {, the ret argument will hold the string returned from the python code and its value will be a plain object, like {message: 'This is a test'}ā€¦

That being said, this code, if (!ret || ret.message == null) return;, checks if nothing was returned from the call then end the callback but if there is something returned then the code assigns it to a variable, like let data = ret.message;ā€¦

Ohh understood
I suppose I need to start reading js then the syntax will be easy to understand
Than you