Any Idea to run JS script on any/specific doctype?

hello i have many js scripts which does almost the same for many doctypes and it is not practical to develop and copy changes to these files and apply minor changes, so i was wondering if any better idea can be done like using one controller ctl.bundle.js or wildcard like “frappe.ui.form.on(”*“)”

thanks in advance

Hi @PyJumper,

If you want to apply the logic for mutiple doctype then apply it in the utils.js in your custom app. then add it in the bundle js.

hooks.py

app_include_js = "your_custom_app.bundle.js"

your_custom_app.bundle.js

import "./utils";

/public/js/utils.js

$(document).on('app_ready', function() {
	$.each(["Opportunity", "Quotation", "Supplier Quotation", 
		"Sales Invoice", "Delivery Note",  "Sales Order",
		"Purchase Invoice", "Purchase Receipt", "Purchase Order"], function(i, doctype) {
			frappe.ui.form.on(doctype, {
				refresh: function(frm) {
					// add you logic
				}
			});
	});
});

Migrate the site, and build the app.

10 Likes

thanks a lot, i was not sure about that :grinning:
if a field exist in doctype and not in another it is fine right ?

You can put your dynamic logic according to the scenario :wink:

1 Like

got it thanks again, here is a modified version if someone wondering

const DOCTYPES = {
    "SALES_INVOICE": "Sales Invoice",
    "PURCHASE_INVOICE": "Purchase Invoice",
    "SALES_ORDER": "Sales Order",
}

$(document).on('app_ready', function() {
    for(let k in DOCS) {
        const DOC = DOCTYPES[k]
        const METHODS = {
            setup: function(frm) {
                // add your logic

            },
            refresh: function(frm) {
                // if we want something to be for specific doctype only we can do lle this
                if(DOC === DOCTYPES.SALES_INVOICE) {
                    console.log(`refresh is on sales invoice`, frm);
                }
                if(DOC === DOCTYPES.SALES_ORDER) {
                    console.log(`refresh is on sales order`, frm);
                }
            },
        }

        // if we want to add handler for specific doctype
        if(DOC === DOCTYPES.SALES_INVOICE) {
            METHODS["custom_my_field_name"] = function(frm) {
                console.log(`custom field is on sales invoice`, frm);
            }
        }


        frappe.ui.form.on(DOC, METHODS);
    }
});
3 Likes

Just to state this explicitly

your_custom_app.bundle.js goes into the same dir as your js file. In this example:

hooks.py:
app_include_js = "your_custom_app.bundle.js"

js files:

/public/js/utils.js
/public/js/your_custom_app.bundle.js
1 Like

Just I need two clarifications:

  1. What’s the need of using seperate js files, although we can use “import statement” and utils function in the same file and then can include in hooks file.

  2. How [app_include_js = “your_custom_app.bundle.js”] works if we not define path starting with /assets/…

From frappe “chat” module i need to override some js fuctions in my custom app.

For example override the below class fuction:

import { create_private_room } from ‘./chat_utils’;

export default class ChatAddRoom {
constructor(opts) {
this.user = opts.user;
this.users_list = […frappe.user.get_emails(), ‘Administrator’];
this.user_email = opts.user_email;
this.users_list = this.users_list.filter(function (user) {
return user != opts.user_email;
});
this.setup();
}

async setup() {
this.add_room_dialog = new frappe.ui.Dialog({
title: __(‘Jobtemp Chat Room’),
fields: [
{
label: __(‘Room Type’),
fieldname: ‘type’,
fieldtype: ‘Select’,
options: [‘Group’, ‘Direct’],
default: ‘Group’,
onchange: () => {
const type = this.add_room_dialog.get_value(‘type’);
const is_group = type === ‘Group’;
this.add_room_dialog.set_df_property(‘room_name’, ‘reqd’, is_group);
this.add_room_dialog.set_df_property(‘users’, ‘reqd’, is_group);
this.add_room_dialog.set_df_property(‘user’, ‘reqd’, !is_group);
},
reqd: true,
},
{
label: __(‘Room Name’),
fieldname: ‘room_name’,
fieldtype: ‘Data’,
depends_on: “eval:doc.type == ‘Group’”,
reqd: true,
},
{
label: __(‘Users’),
fieldname: ‘users’,
fieldtype: ‘MultiSelectPills’,
options: this.users_list,
depends_on: “eval:doc.type == ‘Group’”,
reqd: true,
},
{
label: __(‘User’),
fieldname: ‘user’,
fieldtype: ‘Link’,
options: ‘User’,
depends_on: “eval:doc.type == ‘Direct’”,
},
],
action: {
primary: {
label: __(‘Create’),
onsubmit: (values) => {
let users = this.add_room_dialog.fields_dict.users.get_values();
let room_name = values.room_name;
if (values.type === ‘Direct’) {
users = [values.user];
room_name = ‘Direct Room’;
}
this.handle_room_creation(room_name, users, values.type);
this.add_room_dialog.hide();
},
},
},
});
}

show() {
this.add_room_dialog.show();
}

async handle_room_creation(room_name, users, type) {
try {
await create_private_room(room_name, users, type);
this.add_room_dialog.clear();
} catch (error) {
//pass
}
}
}

located at: /home/xadmin/frappe-bench/apps/chat/chat/public/js/components/chat_add_room.js

I made too many attempts but not able to do. Immediate response would be appreciated!