feat: multistep webforms
This commit is contained in:
parent
87adfb5ebd
commit
ae363d9df2
2 changed files with 183 additions and 1 deletions
|
|
@ -9,6 +9,7 @@ export default class WebForm extends frappe.ui.FieldGroup {
|
|||
frappe.web_form = this;
|
||||
frappe.web_form.events = {};
|
||||
Object.assign(frappe.web_form.events, EventEmitterMixin);
|
||||
this.current_section = 0;
|
||||
}
|
||||
|
||||
prepare(web_form_doc, doc) {
|
||||
|
|
@ -19,12 +20,16 @@ export default class WebForm extends frappe.ui.FieldGroup {
|
|||
|
||||
make() {
|
||||
super.make();
|
||||
this.set_sections();
|
||||
this.set_field_values();
|
||||
this.setup_listeners();
|
||||
if (this.introduction_text) this.set_form_description(this.introduction_text);
|
||||
if (this.allow_print && !this.is_new) this.setup_print_button();
|
||||
if (this.allow_delete && !this.is_new) this.setup_delete_button();
|
||||
if (this.is_new) this.setup_cancel_button();
|
||||
this.setup_primary_action();
|
||||
this.setup_previous_next_button();
|
||||
this.toggle_section();
|
||||
$(".link-btn").remove();
|
||||
|
||||
// webform client script
|
||||
|
|
@ -40,6 +45,79 @@ export default class WebForm extends frappe.ui.FieldGroup {
|
|||
};
|
||||
}
|
||||
|
||||
setup_listeners() {
|
||||
// Event listener for triggering Save/Next button for Multi Step Forms
|
||||
// Do not use `on` event here since that can be used by user which will render this function useless
|
||||
// setTimeout has 200ms delay so that all the base_control triggers for the fields have been run
|
||||
let me = this;
|
||||
|
||||
if (!me.is_multi_step_form) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let field of $(".input-with-feedback")) {
|
||||
$(field).change((e) => {
|
||||
setTimeout(() => {
|
||||
e.stopPropagation();
|
||||
me.toggle_buttons();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
set_sections() {
|
||||
if (this.sections.length) return;
|
||||
|
||||
this.sections = $(`.form-section`);
|
||||
}
|
||||
|
||||
setup_previous_next_button() {
|
||||
let me = this;
|
||||
|
||||
if (!me.is_multi_step_form) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.web-form-footer').after(`
|
||||
<div id="form-step-footer" class="pull-right">
|
||||
<button class="btn btn-primary btn-previous btn-sm ml-2">${__("Previous")}</button>
|
||||
<button class="btn btn-primary btn-next btn-sm ml-2">${__("Next")}</button>
|
||||
</div>
|
||||
`);
|
||||
|
||||
$('.btn-previous').on('click', function () {
|
||||
let is_validated = me.validate_section();
|
||||
|
||||
if (!is_validated) return;
|
||||
|
||||
for (let idx = me.current_section; idx < me.sections.length; idx--) {
|
||||
let is_empty = me.is_previous_section_empty(idx);
|
||||
me.current_section = me.current_section > 0 ? me.current_section - 1 : me.current_section;
|
||||
|
||||
if (!is_empty) {
|
||||
break
|
||||
}
|
||||
}
|
||||
me.toggle_section();
|
||||
});
|
||||
|
||||
$('.btn-next').on('click', function () {
|
||||
let is_validated = me.validate_section();
|
||||
|
||||
if (!is_validated) return;
|
||||
|
||||
for (let idx = me.current_section; idx < me.sections.length; idx++) {
|
||||
let is_empty = me.is_next_section_empty(idx);
|
||||
me.current_section = me.current_section < me.sections.length ? me.current_section + 1 : me.current_section;
|
||||
|
||||
if (!is_empty) {
|
||||
break
|
||||
}
|
||||
}
|
||||
me.toggle_section();
|
||||
});
|
||||
}
|
||||
|
||||
set_field_values() {
|
||||
if (this.doc.name) this.set_values(this.doc);
|
||||
else return;
|
||||
|
|
@ -104,6 +182,103 @@ export default class WebForm extends frappe.ui.FieldGroup {
|
|||
);
|
||||
}
|
||||
|
||||
validate_section() {
|
||||
if (this.allow_incomplete) return true;
|
||||
|
||||
let fields = $(`.form-section:eq(${this.current_section}) .form-control`);
|
||||
let errors = []
|
||||
|
||||
for (let field of fields) {
|
||||
let fieldname = $(field).attr("data-fieldname");
|
||||
if (!fieldname) continue;
|
||||
|
||||
field = this.fields_dict[fieldname];
|
||||
|
||||
if (field.get_value) {
|
||||
let value = field.get_value();
|
||||
if (field.df.reqd && is_null(typeof value === 'string' ? strip_html(value) : value)) errors.push(__(field.df.label));
|
||||
|
||||
if (field.df.reqd && field.df.fieldtype === 'Text Editor' && is_null(strip_html(cstr(value)))) errors.push(__(field.df.label));
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
frappe.msgprint({
|
||||
title: __('Missing Values Required'),
|
||||
message: __('Following fields have missing values:') +
|
||||
'<br><br><ul><li>' + errors.join('<li>') + '</ul>',
|
||||
indicator: 'orange'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
toggle_section() {
|
||||
if (!this.is_multi_step_form) return;
|
||||
|
||||
this.toggle_previous_button();
|
||||
this.hide_sections();
|
||||
this.show_section();
|
||||
this.toggle_buttons();
|
||||
}
|
||||
|
||||
toggle_buttons() {
|
||||
for (let idx = this.current_section; idx < this.sections.length; idx++) {
|
||||
if (this.is_next_section_empty(idx)) {
|
||||
this.show_save_and_hide_next_button();
|
||||
} else {
|
||||
this.show_next_and_hide_save_button();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_next_section_empty(section) {
|
||||
if (section + 1 > this.sections.length) return true;
|
||||
|
||||
let _section = $(`.form-section:eq(${section + 1})`);
|
||||
let visible_controls = _section.find(".frappe-control:not(.hide-control)");
|
||||
|
||||
return !visible_controls.length ? true : false;
|
||||
}
|
||||
|
||||
is_previous_section_empty(section) {
|
||||
if (section - 1 > this.sections.length) return true;
|
||||
|
||||
let _section = $(`.form-section:eq(${section - 1})`);
|
||||
let visible_controls = _section.find(".frappe-control:not(.hide-control)");
|
||||
|
||||
return !visible_controls.length ? true : false;
|
||||
}
|
||||
|
||||
show_save_and_hide_next_button() {
|
||||
$('.btn-next').hide();
|
||||
$('.web-form-footer').show();
|
||||
}
|
||||
|
||||
show_next_and_hide_save_button() {
|
||||
$('.btn-next').show();
|
||||
$('.web-form-footer').hide();
|
||||
}
|
||||
|
||||
toggle_previous_button() {
|
||||
this.current_section == 0 ? $('.btn-previous').hide() : $('.btn-previous').show();
|
||||
}
|
||||
|
||||
show_section() {
|
||||
$(`.form-section:eq(${this.current_section})`).show();
|
||||
}
|
||||
|
||||
hide_sections() {
|
||||
for (let idx=0; idx < this.sections.length; idx++) {
|
||||
if (idx !== this.current_section) {
|
||||
$(`.form-section:eq(${idx})`).hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
let is_new = this.is_new;
|
||||
if (this.validate && !this.validate()) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
"module",
|
||||
"column_break_4",
|
||||
"is_standard",
|
||||
"is_multi_step_form",
|
||||
"published",
|
||||
"login_required",
|
||||
"route_to_success_link",
|
||||
|
|
@ -355,13 +356,19 @@
|
|||
"fieldname": "apply_document_permissions",
|
||||
"fieldtype": "Check",
|
||||
"label": "Apply Document Permissions"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "is_multi_step_form",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Multi Step Form"
|
||||
}
|
||||
],
|
||||
"has_web_view": 1,
|
||||
"icon": "icon-edit",
|
||||
"is_published_field": "published",
|
||||
"links": [],
|
||||
"modified": "2020-08-07 13:12:03.945686",
|
||||
"modified": "2021-11-15 14:12:44.624573",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Web Form",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue