Sections optionnelles
Sections optionnelles
frappe.ui.OptionalSections affiche une rangée de boutons d'ajout, un par section optionnelle d'un formulaire. Cliquer sur un bouton affiche la section en ligne, avec un bouton de suppression qui la masque et remet son bouton d'ajout en place. Le composant convient aux formulaires dont la plupart des champs sont facultatifs : les champs obligatoires restent visibles et les autres n'apparaissent que sur demande.
Il est également exposé sous la forme pratique frappe.ui.optional_sections(opts), qui construit les sections et renvoie l'élément racine.
Une démonstration est disponible dans l'explorateur de composants du bureau (page « Component Explorer », entrée « Optional Sections »).
Prérequis
- Le code s'exécute dans le bureau (desk), où
frappe.ui.buttonest disponible : le composant construit ses boutons avec. - Les deux bundles
optional_sections.bundle.jsetoptional_sections.bundle.csssont chargés avant l'appel.
Chargement
Le composant est distribué dans son propre bundle, chargé à la première utilisation afin de ne pas alourdir les bundles du bureau et du site :
await frappe.require(["optional_sections.bundle.js", "optional_sections.bundle.css"]);
Utilisation
await frappe.require(["optional_sections.bundle.js", "optional_sections.bundle.css"]);
const sections = new frappe.ui.OptionalSections({
label: __("Ajouter d'autres informations"),
sections: [
{ title: __("Contact"), content: () => this.make_contact_fields() },
{ title: __("Coordonnées bancaires"), content: () => this.make_bank_fields() },
],
on_remove: (index) => this.clear_fields(index),
});
body.append(sections.$el);
La forme courte s'enchaîne directement dans un append :
body.append(
frappe.ui.optional_sections({
label: __("Ajouter d'autres informations"),
sections: [{ title: __("Contact"), content: "Champs de contact ici." }],
})
);
Options
| Option | Type | Description |
|---|---|---|
sections | Array | Sections optionnelles du formulaire, décrites ci-dessous. |
label | string | Texte affiché au-dessus des boutons d'ajout, par exemple __("Ajouter d'autres informations"). |
remove_label | string | Libellé du bouton de suppression de chaque section. Par défaut : __("Remove"). |
on_add | function | Appelée avec (index, section) après l'ajout d'une section. |
on_remove | function | Appelée avec (index, section) après la suppression d'une section. La suppression masque la section mais conserve son contenu : réinitialisez vos champs dans ce rappel. |
css_class | string | Classes supplémentaires ajoutées à l'élément racine. |
Chaque entrée de sections accepte les options suivantes :
| Option | Type | Description |
|---|---|---|
title | string | Intitulé de la section, également utilisé comme libellé de son bouton d'ajout. Affiché comme texte, jamais comme HTML. |
content | Element, JQuery, function ou string | Corps de la section. Une fonction est appelée avec l'instance du composant, une seule fois au premier affichage de la section, et doit renvoyer un élément. Une chaîne est affichée comme texte, jamais comme HTML. |
added | boolean | Affiche la section dès le départ. |
Comportement
- Cliquer sur un bouton d'ajout affiche la section en ligne, dans l'ordre déclaré, et masque le bouton ; le bouton de suppression masque la section et remet le bouton d'ajout en place.
- Le contenu d'une section n'est construit qu'à son premier affichage.
- À l'ajout, le focus est placé sur le premier champ de la section (
inputautre qu'une case à cocher ou un champ caché,selectoutextarea), ou à défaut sur le premier bouton de la section. À la suppression, le focus revient au bouton d'ajout. - La rangée des boutons d'ajout est masquée dès que toutes les sections sont ajoutées.
- Chaque section porte l'attribut
data-state="added"oudata-state="removed". La racine porte la classees-optional-sectionset les éléments internes suivent la conventiones-optional-sections__*(par exemplees-optional-sections__buttons). - Les intitulés et les contenus textuels sont rendus comme du texte brut : le composant n'interprète jamais de HTML.
Exemple avec des champs
Lorsque la section contient des champs, construisez-les dans content et réinitialisez-les dans on_remove, car la suppression conserve le contenu :
let fields;
body.append(
frappe.ui.optional_sections({
label: __("Ajouter d'autres informations"),
sections: [
{
title: __("Contact"),
content: () => {
const section_body = document.createElement("div");
fields = new frappe.ui.FieldGroup({
body: section_body,
fields: [
{ fieldtype: "Data", fieldname: "email", label: __("E-mail") },
{ fieldtype: "Column Break", fieldname: "column" },
{ fieldtype: "Data", fieldname: "mobile", label: __("Mobile") },
],
});
fields.make();
return section_body;
},
},
],
on_remove: () => fields.set_values({ email: "", mobile: "" }),
})
);
Méthodes de l'instance
L'instance créée avec new frappe.ui.OptionalSections(opts) expose :
add(index): affiche la section située à l'index donné.remove(index): masque la section située à l'index donné.is_added(index): renvoietruesi la section est affichée.destroy(): retire l'élément du DOM.$eletel: l'élément racine, en jQuery et en élément DOM.
La forme pratique frappe.ui.optional_sections(opts) renvoie l'élément racine en jQuery ; l'instance reste accessible via .data("es-optional-sections") :
const $el = frappe.ui.optional_sections({ sections: [] });
const sections = $el.data("es-optional-sections");
sections.add(0);