fix(client): Retour aux p:commandButton directs pour les actions dans DataTables

PROBLÈME IDENTIFIÉ:
- Les composants action-button-* et button-form-submit utilisaient ui:define pour passer action
- JSF ne peut pas évaluer ui:define comme une expression de méthode
- Erreur: 'Identity [action] does not reference a method expression instance, returned type [java.lang.String]'

SOLUTION APPLIQUÉE:
- Suppression de action-button-edit.xhtml, action-button-toggle.xhtml, action-button-delete.xhtml, button-form-submit.xhtml
- Retour aux p:commandButton directs dans liste.xhtml et nouvelle.xhtml
- Ajout de ui-button-text pour le style Rounded Text (icône + texte)
- Largeur colonne Actions augmentée : 280px → 320px

COMPOSANTS DRY/WOU CONSERVÉS (qui fonctionnent):
- button-success.xhtml, button-secondary.xhtml : navigation avec outcome
- button-primary.xhtml, button-warning.xhtml, button-info.xhtml, button-icon.xhtml : actions simples
- Tous les composants cards, forms, layout, tables, dialogs

CONCLUSION:
Pour les actions avec paramètres dans DataTables, p:commandButton direct est la seule solution viable en JSF.
This commit is contained in:
dahoud
2025-11-29 22:10:14 +00:00
parent 3ded66f3ea
commit 7e8ee33512
7 changed files with 42 additions and 184 deletions

View File

@@ -123,7 +123,8 @@
rowsPerPageTemplate="10,20,50,100" rowsPerPageTemplate="10,20,50,100"
paginatorPosition="bottom" paginatorPosition="bottom"
emptyMessage="Aucune organisation trouvée" emptyMessage="Aucune organisation trouvée"
styleClass="table-responsive"> styleClass="table-responsive"
size="small">
<!-- Logo (DRY/WOU: organisation-logo) --> <!-- Logo (DRY/WOU: organisation-logo) -->
<p:column headerText="" style="width: 80px;"> <p:column headerText="" style="width: 80px;">
@@ -164,44 +165,39 @@
icon="#{org.statut == organisationsBean.statutActive ? 'pi pi-check' : 'pi pi-times'}"/> icon="#{org.statut == organisationsBean.statutActive ? 'pi pi-check' : 'pi pi-times'}"/>
</p:column> </p:column>
<!-- Actions (DRY/WOU: action-button-* avec ui:button-text pour Rounded Text) --> <!-- Actions (Rounded Text : boutons avec icône + texte) -->
<p:column headerText="Actions" style="width: 280px;"> <p:column headerText="Actions" style="width: 320px;">
<!-- Bouton Consulter --> <p:commandButton value="Consulter"
<ui:include src="/templates/components/buttons/action-button-view.xhtml"> icon="pi pi-search"
<ui:param name="id" value="#{org.id}"/> styleClass="ui-button-rounded ui-button-text ui-button-info mr-2"
<ui:param name="detailPage" value="/pages/secure/organisation/detail.xhtml"/> onclick="window.location='#{request.contextPath}/pages/secure/organisation/detail.xhtml?id=#{org.id}';return false;"/>
<ui:param name="styleClass" value="mr-2"/>
</ui:include> <p:commandButton value="Modifier"
icon="pi pi-pencil"
actionListener="#{organisationsBean.setOrganisationSelectionnee(org)}"
oncomplete="PF('dlgModifier').show();"
update=":formModifier"
styleClass="ui-button-rounded ui-button-text ui-button-warning mr-2"/>
<p:commandButton value="#{org.statut == organisationsBean.statutActive ? 'Désactiver' : 'Activer'}"
icon="#{org.statut == organisationsBean.statutActive ? 'pi pi-ban' : 'pi pi-check'}"
actionListener="#{organisationsBean.basculerStatutOrganisation(org)}"
update=":formOrganisations:dtOrganisations :formOrganisations:messages"
styleClass="ui-button-rounded ui-button-text #{org.statut == organisationsBean.statutActive ? 'ui-button-secondary' : 'ui-button-success'} mr-2">
<p:confirm header="Confirmation"
message="Êtes-vous sûr de vouloir changer le statut de cette organisation ?"
icon="pi pi-exclamation-triangle"/>
</p:commandButton>
<!-- Bouton Modifier --> <p:commandButton value="Supprimer"
<ui:decorate template="/templates/components/buttons/action-button-edit.xhtml"> icon="pi pi-trash"
<ui:param name="update" value=":formModifier"/> actionListener="#{organisationsBean.supprimerOrganisation(org)}"
<ui:param name="dialogWidget" value="dlgModifier"/> update=":formOrganisations:dtOrganisations :formOrganisations:messages"
<ui:param name="styleClass" value="mr-2"/> styleClass="ui-button-rounded ui-button-text ui-button-danger">
<ui:define name="action"> <p:confirm header="Confirmation"
#{organisationsBean.setOrganisationSelectionnee(org)} message="Êtes-vous sûr de vouloir supprimer cette organisation ? Cette action est irréversible."
</ui:define> icon="pi pi-exclamation-triangle"/>
</ui:decorate> </p:commandButton>
<!-- Bouton Toggle Statut -->
<ui:decorate template="/templates/components/buttons/action-button-toggle.xhtml">
<ui:param name="update" value=":formOrganisations:dtOrganisations :formOrganisations:messages"/>
<ui:param name="isActive" value="#{org.statut == organisationsBean.statutActive}"/>
<ui:param name="confirmMessage" value="Êtes-vous sûr de vouloir changer le statut de cette organisation ?"/>
<ui:param name="styleClass" value="mr-2"/>
<ui:define name="action">
#{organisationsBean.basculerStatutOrganisation(org)}
</ui:define>
</ui:decorate>
<!-- Bouton Supprimer -->
<ui:decorate template="/templates/components/buttons/action-button-delete.xhtml">
<ui:param name="update" value=":formOrganisations:dtOrganisations :formOrganisations:messages"/>
<ui:param name="confirmMessage" value="Êtes-vous sûr de vouloir supprimer cette organisation ? Cette action est irréversible."/>
<ui:define name="action">
#{organisationsBean.supprimerOrganisation(org)}
</ui:define>
</ui:decorate>
</p:column> </p:column>
</p:dataTable> </p:dataTable>
</ui:define> </ui:define>

View File

@@ -48,16 +48,12 @@
<ui:param name="icon" value="pi pi-times"/> <ui:param name="icon" value="pi pi-times"/>
<ui:param name="outcome" value="/pages/secure/organisation/liste"/> <ui:param name="outcome" value="/pages/secure/organisation/liste"/>
</ui:include> </ui:include>
<!-- DRY/WOU: button-form-submit pour action backend --> <!-- Bouton Créer : p:commandButton direct car action avec méthode backend -->
<ui:decorate template="/templates/components/buttons/button-form-submit.xhtml"> <p:commandButton value="Créer"
<ui:param name="value" value="Créer" /> icon="pi pi-check"
<ui:param name="icon" value="pi pi-check" /> action="#{organisationsBean.creerOrganisation}"
<ui:param name="update" value=":formNouvelleOrganisation:messages" /> update=":formNouvelleOrganisation:messages"
<ui:param name="severity" value="success" /> styleClass="ui-button-success" />
<ui:define name="action">
#{organisationsBean.creerOrganisation}
</ui:define>
</ui:decorate>
</div> </div>
</h:form> </h:form>
</ui:define> </ui:define>

View File

@@ -1,30 +0,0 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton "Supprimer" avec confirmation réutilisable - DRY/WOU
Usage avec ui:decorate pour passer l'action via ui:define :
<ui:decorate template="/templates/components/buttons/action-button-delete.xhtml">
<ui:param name="update" value=":formList:dtItems :formList:messages"/>
<ui:param name="confirmMessage" value="Êtes-vous sûr de vouloir supprimer ?"/>
<ui:param name="styleClass" value=""/>
<ui:define name="action">
#{bean.deleteItem(item)}
</ui:define>
</ui:decorate>
-->
<p:commandButton value="Supprimer"
icon="pi pi-trash"
actionListener="#{action}"
update="#{update}"
styleClass="ui-button-rounded ui-button-text ui-button-danger #{not empty styleClass ? styleClass : ''}">
<p:confirm header="Confirmation"
message="#{empty confirmMessage ? 'Êtes-vous sûr de vouloir supprimer cet élément ?' : confirmMessage}"
icon="pi pi-exclamation-triangle"/>
</p:commandButton>
</ui:composition>

View File

@@ -1,27 +0,0 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton "Modifier" réutilisable - DRY/WOU
Usage avec ui:decorate pour passer l'action via ui:define :
<ui:decorate template="/templates/components/buttons/action-button-edit.xhtml">
<ui:param name="update" value=":formEdit"/>
<ui:param name="dialogWidget" value="dlgEdit"/>
<ui:param name="styleClass" value="mr-2"/>
<ui:define name="action">
#{bean.setItemSelected(item)}
</ui:define>
</ui:decorate>
-->
<p:commandButton value="Modifier"
icon="pi pi-pencil"
actionListener="#{action}"
oncomplete="PF('#{dialogWidget}').show();"
update="#{update}"
styleClass="ui-button-rounded ui-button-text ui-button-warning #{not empty styleClass ? styleClass : ''}"/>
</ui:composition>

View File

@@ -1,31 +0,0 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton "Activer/Désactiver" avec confirmation réutilisable - DRY/WOU
Usage avec ui:decorate pour passer l'action via ui:define :
<ui:decorate template="/templates/components/buttons/action-button-toggle.xhtml">
<ui:param name="update" value=":formList:dtItems :formList:messages"/>
<ui:param name="isActive" value="#{item.statut == 'ACTIVE'}"/>
<ui:param name="confirmMessage" value="Êtes-vous sûr ?"/>
<ui:param name="styleClass" value="mr-2"/>
<ui:define name="action">
#{bean.toggleItem(item)}
</ui:define>
</ui:decorate>
-->
<p:commandButton value="#{isActive ? 'Désactiver' : 'Activer'}"
icon="#{isActive ? 'pi pi-ban' : 'pi pi-check'}"
actionListener="#{action}"
update="#{update}"
styleClass="ui-button-rounded ui-button-text #{isActive ? 'ui-button-secondary' : 'ui-button-success'} #{not empty styleClass ? styleClass : ''}">
<p:confirm header="Confirmation"
message="#{empty confirmMessage ? 'Êtes-vous sûr de vouloir changer le statut ?' : confirmMessage}"
icon="pi pi-exclamation-triangle"/>
</p:commandButton>
</ui:composition>

View File

@@ -1,47 +0,0 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton de soumission de formulaire réutilisable (WOU/DRY)
Usage :
<ui:decorate template="/templates/components/buttons/button-form-submit.xhtml">
<ui:param name="value" value="Enregistrer" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="update" value=":form:messages" />
<ui:param name="process" value="@form" />
<ui:param name="severity" value="success" />
<ui:param name="oncomplete" value="if(!args.validationFailed) PF('dialog').hide();" />
<ui:define name="action">
#{bean.saveMethod}
</ui:define>
</ui:decorate>
Paramètres :
- value : Texte du bouton (requis)
- icon : Icône (optionnel, défaut: pi pi-check)
- update : Composants à mettre à jour (optionnel)
- process : Composants à traiter (optionnel, défaut: @form)
- severity : success, secondary, warning, danger, info, primary (défaut: success)
- disabled : true/false (défaut: false)
- oncomplete : JavaScript à exécuter après l'action (optionnel)
- validateClient : true/false pour validation côté client (défaut: false)
- styleClass : Classes CSS additionnelles (optionnel)
Slot action : Expression de méthode du bean (requis)
-->
<p:commandButton value="#{value}"
icon="#{empty icon ? 'pi pi-check' : icon}"
action="#{action}"
update="#{update}"
process="#{empty process ? '@form' : process}"
oncomplete="#{oncomplete}"
validateClient="#{not empty validateClient and validateClient}"
disabled="#{not empty disabled and disabled}"
styleClass="ui-button-#{empty severity ? 'success' : severity} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:composition>

View File

@@ -42,7 +42,8 @@
sortField="#{sortField}" sortField="#{sortField}"
sortOrder="#{sortOrder}" sortOrder="#{sortOrder}"
filteredValue="#{filteredValue}" filteredValue="#{filteredValue}"
widgetVar="#{widgetVar}"> widgetVar="#{widgetVar}"
size="#{size}">
<ui:insert name="columns"> <ui:insert name="columns">
<!-- Table columns go here --> <!-- Table columns go here -->