PrimeFaces CommandButton Action not called inside Composite

Fernando Bonafé picture Fernando Bonafé · Oct 21, 2011 · Viewed 30.2k times · Source

In the code bellow the jsf html commandButton action is called perfectly. But primefaces commandButton action is not called.

<ui:component          
              xmlns="http://www.w3.org/1999/xhtml" 
            xmlns:f="http://java.sun.com/jsf/core"
            xmlns:h="http://java.sun.com/jsf/html"
           xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:p="http://primefaces.prime.com.tr/ui"
    xmlns:composite="http://java.sun.com/jsf/composite">

    <composite:interface>
        <composite:attribute 
            name="managedBean"          
            type="java.lang.Object"
            required="true">                    
        </composite:attribute>
    </composite:interface>

    <composite:implementation>
        <f:view contentType="text/html"> 
            <h:form id="componentes">  
                <h:panelGrid columns="3">
                    <h:panelGroup>              
                        <h:outputText 
                              escape = "false" 
                               value = "#{cc.attrs.managedBean['value']}"       
                            rendered = "#{!cc.attrs.managedBean['editing']}"/> 
                        <p:editor 
                            widgetVar = "editor" 
                                value = "#{cc.attrs.managedBean.value}" 
                             rendered = "#{cc.attrs.managedBean.editing}"/>
                    </h:panelGroup>
                    <!-- ACTION IS CALLED -->                                 
                    <h:commandButton 
                                action = "#{cc.attrs.managedBean.toogleEditing}" 
                                 value = "#{cc.attrs.managedBean.editing?'Back':'Edit'}" 
                                update = "componentes"/>

                                    <!-- ACTION IS NOT CALLED -->           
                    <p:commandButton 
                                action = "#{cc.attrs.managedBean.toogleEditing}" 
                                 value = "#{cc.attrs.managedBean.editing?'Back':'Edit'}" 
                                update = "componentes"/>
                </h:panelGrid>
            </h:form>                    
        </f:view>
    </composite:implementation>
</ui:component>

If place the same code is outside a composite (a normal xhtml page), both work fine:

<!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html 
    xml:lang="pt" 
        lang="pt"
       xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:f="http://java.sun.com/jsf/core"
     xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
     xmlns:p="http://primefaces.prime.com.tr/ui">

    <h:head id="head">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Item de Texto</title>
    </h:head>
    <h:body id="body">          
        <f:view contentType="text/html"> 
            <h:form id="componentes">  
                <h:panelGrid columns="3">
                    <h:panelGroup>              
                        <h:outputText 
                              escape = "false" 
                               value = "#{editableHTMLText.value}" 
                            rendered = "#{!editableHTMLText.editing}"/>
                        <p:editor 
                            widgetVar = "editor" 
                                value = "#{editableHTMLText.value}" 
                             rendered = "#{editableHTMLText.editing}"/>
                    </h:panelGroup>

                                    <!-- ACTION IS CALLED -->                         
                    <h:commandButton 
                                action = "#{editableHTMLText.toogleEditing}" 
                                 value = "#{editableHTMLText.editing?'Back':'Edit'}" 
                                update = "componentes"/>

                                    <!-- ACTION IS CALLED -->
                    <p:commandButton 
                                action = "#{editableHTMLText.toogleEditing}" 
                                 value = "#{editableHTMLText.editing?'Back':'Edit'}" 
                                update = "componentes"/>
                </h:panelGrid>
            </h:form>                    
        </f:view>
    </h:body>
</html>

This is the bean code:

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;


@ManagedBean
@SessionScoped
public class EditableHTMLText implements Serializable{

    /**
     * 
     */
    private static final long   serialVersionUID    = 8439126615761864409L;

    private String              value               = "Test<br>of<br>HTML<br>text<br><b>ITEM</b><br>";
    private boolean             editing             = false;


    public void toogleEditing(){

        this.setEditing(!this.isEditing());
        System.out.println("Editing State: " + this.editing);
    }


    public String getValue(){

        return value;
    }


    public void setValue(String value){

        this.value = value;
    }


    public boolean isEditing(){

        return editing;
    }


    public void setEditing(boolean editing){

        this.editing = editing;
    }

}

Any suggestions?

Answer

Mauro Molinari picture Mauro Molinari · Dec 15, 2014

Today I hit this exact same problem with PrimeFaces 5.1. In my case I had no nested forms and I was already setting the process attribute on the p:commandButton with the form elements I wanted to be processed. However this didn't work yet.

The "solution" was to add @this to the list of components to process, like this:

<p:commandButton process="myFormField1 myFormField2 @this">

Without @this (which is not usually needed, since the button itself shouldn't need to be processed/validated) I found no way to make any of these to work inside a composite:

  • <p:commandButton action="#{bean.myAction}"...>
  • <p:commandButton type="button"> with nested <p:ajax event="click" action="#{bean.myAction}"...>
  • <p:commandButton type="button" onclick="myAction()"> with associated <p:remoteCommand name="myAction" action="#{bean.myAction}">

By debugging the application, I saw that the validation and update model phases were correctly executed, but then in the invoke application phase no queued event was present and hence no action was performed. Actually, I could specify anything I liked inside the action and actionListener attribute values of <p:commandButton> without having either PrimeFaces or JSF complain in any way.

These, instead, do work as they should, but you don't have partial processing in place, so they may not be a viable solution:

  • <p:commandButton action="#{bean.myAction}" ajax="false"...>
  • <p:commandButton type="button"...> with nested <f:ajax event="click" action="#{bean.myAction}"...>

It must be a PrimeFaces bug.