web-dev-qa-db-fra.com

Mise à jour de l'ensemble <p: ​​dataTable> à la fin de <p: ​​ajax event = "cellEdit">

Je ne parviens pas à rétablir le rendu d'un objet datable PrimeFaces une fois qu'une cellule a été modifiée. La modification de la valeur d'une cellule peut modifier les entrées des autres cellules, d'où la nécessité d'actualiser l'ensemble du tableau. 

Voici la page JSF:

<h:form id="testForm">
    <p:outputPanel id="testContainer">

        <p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">

            <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />

            <p:column headerText="Col1">  
                <p:cellEditor>
                    <f:facet name="output"><h:outputText value="#{entry.col1}" /></f:facet>
                    <f:facet name="input"><p:inputText value="#{entry.col1}" /></f:facet>
                </p:cellEditor> 
            </p:column>

            <p:column headerText="Col2">
                <p:cellEditor>
                    <f:facet name="output"><h:outputText value="#{entry.col2}" /></f:facet>
                    <f:facet name="input"><p:inputText value="#{entry.col2}" /></f:facet>
                </p:cellEditor>  
            </p:column>

        </p:dataTable>

        <p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />

    </p:outputPanel>                                    
</h:form>

Et voici le haricot de renfort:

@ManagedBean(name = "tableBean", eager = false)
@ViewScoped 
public class TableBean {

    public TableBean() {
        RowData entry = new RowData("a1", "b1");
        entries.add(entry);
        entry = new RowData("a2", "b2");
        entries.add(entry);
        entry = new RowData("a3", "b3");
        entries.add(entry);
    }

    public class RowData {

        private String col1;
        private String col2;

        public RowData(String col1, String col2) {
            this.col1 = col1;
            this.col2 = col2;
        }

        public String getCol1() {
            return col1;
        }

        public void setCol1(String col1) {
            this.col1 = col1;
        }

        public String getCol2() {
            return col2;
        }

        public void setCol2(String col2) {
            this.col2 = col2;
        }
    }

    private ArrayList<RowData> entries = new ArrayList<RowData>();

    public List<RowData> getData() {
        return entries;
    }

    public void onCellEdit(CellEditEvent event) {
        entries.get(event.getRowIndex()).setCol1("Dummy Col 1");
        entries.get(event.getRowIndex()).setCol2("Dummy Col 2");        
    }   
}

Lors de l'inclusion de update = ": testForm: testContainer" dans l'événement cellEdit AJAX, la modification d'une valeur de cellule supprime le datatable à l'écran et ne restitue que le contenu de la cellule (avec le bouton). Je ne comprends pas pourquoi. . Lorsque l'attribut update n'est pas spécifié, la table reste à l'écran avec la cellule active mise à jour, mais aucune des autres cellules n'est mise à jour (comme prévu).

Le comportement souhaité peut être obtenu (de manière non automatisée) en ne spécifiant pas l'attribut de mise à jour dans l'événement AJAX cellEdit et en cliquant sur le bouton Rediffuser après avoir modifié la valeur d'une cellule. Comment puis-je y parvenir de manière automatisée et pourquoi l'attribut update ne fonctionne-t-il pas comme prévu?

J'utilise PrimeFaces 4.0.

31
Franzl

Les événements rowEdit et cellEdit ne sont pas mis à jour/restitués par la conception même de la table, même s'ils ne sont pas explicitement spécifiés dans l'attribut update. C'est la conséquence de la tentative un peu trop zélée de PrimeFaces de minimiser la taille de la réponse. Cela a du sens dans la plupart des cas, mais pas spécifiquement dans votre cas. Cela vaut la peine de signaler un problème. 

En attendant, jusqu'à ce qu'ils résolvent ce problème, votre meilleur choix est d'utiliser <p:remoteCommand> pour appeler la méthode d'écoute souhaitée et effectuer une mise à jour complète de la table.

Récrire

<p:dataTable ...>
    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
    ...
</p:dataTable>

à

<p:remoteCommand name="onCellEdit" action="#{tableBean.onCellEdit}" update="testContainer" />
<p:dataTable ...>
    <p:ajax event="cellEdit" oncomplete="onCellEdit()" />
    ...
</p:dataTable>
55
BalusC

La solution BaLusC n'a pas fonctionné directement pour moi. Le onCellEdit a besoin d'un CellEditEvent en tant que paramètre. Ma solution de contournement est la suivante:

<p:remoteCommand name="onCellEdit" update="testContainer" />
<p:dataTable ...>
    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="onCellEdit()" />
    ...
</p:dataTable>
20
Tim Long

Si aucune des solutions ne fonctionnait pour vous, cela fonctionnait pour moi

<p:dataTable ... id="theId" widgetVar="theWidget" ...>
                <p:ajax event="rowEdit" listener="#{...}"
                        oncomplete="PF('theWidget').filter()"/> 
....

J'appelle la méthode de filtre sur le widget PF sur ajax complete, toute méthode qui effectue un "rechargement" de la table devrait fonctionner, j'ai utilisé le filtre car ma table avait des filtres de colonnes.

5
Lance Reid

J'ai testé votre code. J'ai d'abord déplacé p: commandButton sur p: outputPanel. Voici le code modifié:

<h:form id="testForm">
            <p:outputPanel id="testContainer">

                <p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">

                    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />

                    (...)

                </p:dataTable>
            </p:outputPanel>
            <p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />
        </h:form>

Je pense que ce code ne fonctionne pas correctement. si vous changez quelque chose dans la table, le p: ajax à chaque fois rend une table complète. Ainsi, le programme charge les données de base à partir du constructeur TableBean et supprime les nouvelles données.

basic data

Si j'omets votre code p: ajax, aucune nouvelle donnée ne disparaît de l'écran. La refreshButton p: commandButton fonctionne correctement.

Lors de l'inclusion de update = ": testForm: testContainer" dans cellEdit AJAX, modifier une valeur de cellule supprime le datatable à l'écran et rend uniquement le contenu de la cellule (avec le bouton) - je ne le fais pas comprendre pourquoi c'est.

Je pense que c'est une mauvaise conception, ajoutez update=":testForm:testContainer" à ajax, car il met à jour votre outputPanel plus qu'excepté (la première fois que vous travaillez correctement, la deuxième fois ne peut pas éditer la cellule, car le programme met à jour plusieurs fois). 

Je ne sais pas quel est ton objectif. Si vous voulez rendre la table sans un bouton de commande, pouvez-vous spécifier un événement javascript ou un message p: et ceci disparaît, vous pouvez rendre la table.

Je pense que si vous omettez update dans p: ajax ou spécifiez la mise à jour d'un message p: et déplacez p.commandButton hors de testContainer votre code démarre correctement.

0
herry

Après 5 ans, ce problème existe toujours. Malheureusement, bien que la solution de Baukes soit extrêmement utile et qu'elle comprenne des informations importantes, elle est encore incomplète, comme l'a déjà indiqué ltlBeBoy dans son commentaire. Les modifications ultérieures sans modification conduisent à un état de table incohérent, où aucune autre modification n'est possible. La raison en est que la mise à jour à distance oncomplete intervient après que le mode d'édition de la nouvelle cellule est déjà activé. Le mode d’édition de la nouvelle cellule est donc détruit par la mise à jour. Cependant, la mise à jour ne peut pas être effectuée dans Ajax listener tableBean#onCellEdit, car cela afficherait la table par erreur avec une seule cellule.

La solution consiste à exécuter la mise à jour dans le programme d'écoute de commandes à distance et uniquement si un changement survient. Ainsi, dans tableBean, vous implémentez une mise à jour programmatique, un écouteur distant et un indicateur indiquant le changement:

public static void update(String id) {
   PrimeFaces pf = PrimeFaces.current(); //RequestContext.getCurrentInstance() for <PF 6.2
   if(pf.isAjaxRequest()) pf.ajax().update(id);
}

/** Whether onCellEdit changed the value */
boolean onCellEditChange;

public void onCellEditRemote() { 
    if(!onCellEditChange) update("testContainer");
}

public void onCellEdit(CellEditEvent event) {
    ...  onCellEditChange= /*Change happend*/ ...
}

La commande distante n'a plus d'attribut de mise à jour:

<p:remoteCommand name="onCellEdit" actionListener="#{tabelBean.onCellEditRemote}"/>
0
Marc Dzaebel