class CustomControlAttach extends frappe.ui.form.ControlAttach {
clear_attachment() {
let me = this;
if (this.frm) {
// Remove the file from the form and refresh
me.parse_validate_and_set_in_model(null);
me.refresh();
me.frm.doc.docstatus == 1 ? me.frm.save("Update") : me.frm.save();
} else {
// Handle the case where there's no form context
this.dataurl = null;
this.fileobj = null;
this.set_input(null);
this.parse_validate_and_set_in_model(null);
this.refresh();
}
}
}
Here i want to change the default functionality of Attach button by removing remove attach functionality how can i do that?
that custom class file added in hooks in app_include_js
but standard code running why?
it is not a doctype class it is a javascript class?
NCP
July 22, 2024, 8:44am
4
You have to check the example of hrms:
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.provide("hrms.hr");
hrms.hr.AttendanceControlPanel = class AttendanceControlPanel extends frappe.ui.form.Controller {
onload() {
this.frm.set_value("att_fr_date", frappe.datetime.get_today());
this.frm.set_value("att_to_date", frappe.datetime.get_today());
}
refresh() {
this.frm.disable_save();
this.show_upload();
this.setup_import_progress();
}
custom js file
hooks.py
I added like this but not working it is correct?
NCP
July 22, 2024, 9:24am
6
No.
Again check the example of india-compliance app.
1 Like
How to override js class in frappe>
Created one file attach.js in custom app>
// Define the custom class extending frappe.ui.form.ControlAttach
class CustomControlAttach extends frappe.ui.form.ControlAttach {
// Override the clear_attachment method
clear_attachment() {
console.log("Custom clear_attachment method is loaded and executed"); // Add this line
let me = this;
if (this.frm) {
// Remove the file from the form and refresh
me.parse_validate_and_set_in_model(null);
me.refresh();
me.frm.doc.docstatus == 1 ? me.frm.save("Update") : me.frm.save();
} else {
// Handle the case where there's no form context
this.dataurl = null;
this.fileobj = null;
this.set_input(null);
this.parse_validate_and_set_in_model(null);
this.refresh();
}
}
}
// Ensure to use your custom class in the form instead of the default ControlAttach
frappe.ui.form.ControlAttach = CustomControlAttach;
Created project_name.bundle.js file >
import "./attach.js";
Added in Hooks >
app_include_js = [
"project_name.bundle.js"
]
Thanks @NCP for guidance
3 Likes
hyaray
October 24, 2024, 12:23pm
8
these class are defined to frapps
namespace, It works.
My question is: how to override class defined by export default class XXX
?
EX: class export default class GridRow
in grid_row.js
.
saloni
January 2, 2025, 6:30am
9
I did same My app name is company
1 create file attach.js
file path -->apps/company/company/public/js/attach.js
frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.ControlData {
make_input() {
let me = this;
this.$input = $('<button class="btn btn-default btn-sm btn-attach">')
.html(__("Attach"))
.prependTo(me.input_area)
.on({
click: function () {
me.on_attach_click();
},
attach_doc_image: function () {
me.on_attach_doc_image();
},
});
this.$value = $(
`<div class="attached-file flex justify-between align-center">
<div class="ellipsis">
${frappe.utils.icon("es-line-link", "sm")}
<a class="attached-file-link" target="_blank"></a>
</div>
<div>
<a class="btn btn-xs btn-default" data-action="reload_attachment">${__("Reload File")}</a>
<a class="btn btn-xs btn-default" data-action="clear_attachment">${__("Clear")}</a>
</div>
</div>`
)
.prependTo(me.input_area)
.toggle(false);
this.input = this.$input.get(0);
this.set_input_attributes();
this.has_input = true;
frappe.utils.bind_actions_with_object(this.$value, this);
this.toggle_reload_button();
}
clear_attachment() {
let me = this;
if (this.frm) {
me.parse_validate_and_set_in_model(null);
me.refresh();
me.frm.attachments.remove_attachment_by_filename(me.value, async () => {
await me.parse_validate_and_set_in_model(null);
me.refresh();
// me.frm.doc.docstatus == 1 ? me.frm.save("Update") : me.frm.save();
});
} else {
this.dataurl = null;
this.fileobj = null;
this.set_input(null);
this.parse_validate_and_set_in_model(null);
this.refresh();
}
}
reload_attachment() {
if (this.file_uploader) {
this.file_uploader.uploader.upload_files();
}
}
on_attach_click() {
this.set_upload_options();
this.file_uploader = new frappe.ui.FileUploader(this.upload_options);
}
on_attach_doc_image() {
this.set_upload_options();
this.upload_options.restrictions.allowed_file_types = ["image/*"];
this.file_uploader = new frappe.ui.FileUploader(this.upload_options);
}
set_upload_options() {
let options = {
allow_multiple: false,
on_success: (file) => {
this.on_upload_complete(file);
this.toggle_reload_button();
},
restrictions: {},
};
if (this.frm) {
options.doctype = this.frm.doctype;
options.docname = this.frm.docname;
options.fieldname = this.df.fieldname;
options.make_attachments_public = this.df.make_attachment_public
? 1
: this.frm.meta.make_attachments_public;
}
if (this.df.options) {
Object.assign(options, this.df.options);
}
this.upload_options = options;
}
set_input(value, dataurl) {
this.last_value = this.value;
this.value = value;
if (this.value) {
// value can also be using this format: FILENAME,DATA_URL
// Important: We have to be careful because normal filenames may also contain ","
let file_url_parts = this.value.match(/^([^:]+),(.+):(.+)$/);
let filename;
if (file_url_parts) {
filename = file_url_parts[1];
dataurl = file_url_parts[2] + ":" + file_url_parts[3];
}
if (this.$input && this.$value) {
this.$input.toggle(false);
this.$value
.toggle(true)
.find(".attached-file-link")
.html(filename || this.value)
.attr("href", dataurl || this.value);
} else {
this.$wrapper.html(`
<div class="attached-file flex justify-between align-center">
<div class="ellipsis">
<a href="${dataurl || this.value}" target="_blank">${filename || this.value}</a>
</div>
</div>
`);
}
} else {
this.$input.toggle(true);
this.$value.toggle(false);
}
}
get_value() {
return this.value || null;
}
async on_upload_complete(attachment) {
if (this.frm) {
await this.parse_validate_and_set_in_model(attachment.file_url);
this.frm.attachments.update_attachment(attachment);
// this.frm.doc.docstatus == 1 ? this.frm.save("Update") : this.frm.save();
}
this.set_value(attachment.file_url);
}
toggle_reload_button() {
this.$value
.find('[data-action="reload_attachment"]')
.toggle(this.file_uploader && this.file_uploader.uploader.files.length > 0);
}
};
2 create company.bundle.js file
fiel path —>apps/company/company/public/js/company.bundle.js
import "./attach.js";
3 add bundle.js in hooks
app_include_js = "company.bundle.js"
4 bench build
bench clear-cache
But this is not working ,I want to disable auto save while upload image