4 Replies Latest reply on May 15, 2011 3:56 PM by fotakis

    a4j:commandButton actionListener Facelets composition

    fotakis

      Hello all,

       

      I am struggling to get my head around JSF 2 the lifecycle, the new default view handler Facelets and of course RichFaces 4 . I did do a project about 2 years ago with the same stack, but other versions.

       

      My biggest issue with all of this, is that when you read over the docummentation and how things are "supposed" to work, just don't, you are thrown entirelly out of your learning curve.  Well this is what is going on with me right now.

       

      I am attempting to abstract the well know rich:modalPanel in to a custom xhtml source Facelet taglib.

       

      My Modal Panel - modalPanel.xhtml

       

       

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:f="http://java.sun.com/jsf/core"
            xmlns:rich="http://richfaces.org/rich"
            xmlns:a4j="http://richfaces.org/a4j"
            xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:c="http://java.sun.com/jstl/core"
              >
      
      
          <ui:composition>
      
      
              <rich:popupPanel id="modalPanel_#{id}"
                               modal="true"
                               autosized="false"
                               minWidth="#{width}" >
      
      
                  <!---->
                  <a4j:outputPanel>
                  <h:form id="modalPanel_#{id}_form">
                          <ui:insert />
                          <a4j:commandButton value="Cancel"
                                             immediate="true"
                                             actionListener="#{item[cancelAction]}">
                              <rich:componentControl target="modalPanel_#{id}" event="onclick" operation="hide" />
                          </a4j:commandButton>
                          <a4j:commandButton
                                  value="Save"
                                  actionListener="#{item[saveAction]}"
                                  oncomplete="Existanze.modalPanel.doclose(#{empty facesContext.maximumSeverity},'#{id}')"
                                  render="#{rerender}"
                                  />
      
      
      
      
                      <script type="text/javascript">
      
      
                          //do all the logic here under our namespace
                          if (typeof Existanze == 'undefined') var Existanze= {};
                          if (!Existanze.modalPanel) Existanze.modalPanel= {};
      
      
                          Existanze.modalPanel.doclose = function(valid, id) {
                              var modalId = 'modalPanel_'+id;
                              if(valid){
                                  /*
                                  https://issues.jboss.org/browse/RF-10221
                                   */
                                  RichFaces.$(modalId).hide();
                              }
                          };
      
      
                      </script>
                  </h:form>
                  </a4j:outputPanel>
              </rich:popupPanel>
      
      
          </ui:composition>
      </html>
      
      

       

      The problem I am facing is with the aj4:commandButton actionListener method. This is giving a PropertyNotFoundException for the 'item' identifier, which makes me realize that the #{item} parameter is not being properly set.

       

       

      I include the above template into a simple view like so.

       

       

      <ui:composition template="/WEB-INF/facelets/layout.xhtml"
          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:a4j="http://richfaces.org/a4j"
          xmlns:rich="http://richfaces.org/rich"
          xmlns:ex="http://www.existanze.com/jsf">
      
          <ui:define name="title">this is a complete facelets page</ui:define>
          <ui:define name="header">
          </ui:define>
          <ui:define name="body">
      
      
              <h1>
                  <h:form>
                      Bus Services
                      <a4j:commandButton
                              image="/static/images/ui/add.png"
                              onclick="#{rich:component('modalPanel_addService')}.show()"
                              >
                      </a4j:commandButton>
                  </h:form>
              </h1>
              <ex:modalPanel
                      id="addService"
                      item="#{serviceServicesBean}"
                      cancelAction="resetBean"
                      saveAction="addBean"
                      width="200"
                      rerender="detailsTablePanel"
                      >
      
      
                  <h:inputText id="serviceName" value="#{serviceServicesBean.simpleBean.message}" label="Service Name"/>
                  <rich:message for="serviceName" ajaxRendered="true"/>
              </ex:modalPanel>
          </ui:define>
      </ui:composition>
      
      

       

       

      The serviceServicesBean is a ViewScope bean, and it is very simple.

       

      @Component
      @Scope("view")
      public class ServiceServicesBean implements Serializable{
      
      
          private Logger logger = LoggerFactory.getLogger(ServiceServicesBean.class);
      
      
          SimpleBean simpleBean;
      
      
          @Autowired
          ServicesService servicesService;
      
      
          @PostConstruct
          public void initBean(){
              logger.debug("Initializing ServiceServicesbean");
      
      
              simpleBean = new SimpleBean();
      
      
          }
      
      
          public SimpleBean getSimpleBean() {
              return simpleBean;
          }
      
      
          //this is now an action
          public void addBean(){
              logger.debug("Action called");
      
      
              try{
      
      
                  List<Service> failed = servicesService.addServices(Service.generate(null, simpleBean.getMessage()));
                  simpleBean=new SimpleBean();
      
      
                  //if it is successfull we should let the session bean know
      
      
              }catch (DataIntegrityViolationException e){
                  FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                          "Duplicate Value",
                          "This is a duplication value");
      
      
                  FacesContext.getCurrentInstance().addMessage("modalPanel_addService_form:serviceName", fm);
              }
          }
      
      
          public void resetBean(){
              logger.debug("Resetting Bean");
              simpleBean = new SimpleBean();
          }
      
      
      }
      
      

       

       

      I have read over every possible forum link, and jira bugs, which had the exact same problem and the ones bellow seem to be the most relevant, by I still have problems with this:

       

      https://issues.jboss.org/browse/RF-10781

      http://community.jboss.org/thread/164032?tstart=0

       

       

      Note that if I call #{item[cancelAction]} in action instead of actionListener, the action in the bean is called.

       

      Please I am about to pull my hair out, any insight will be much appreciated.

       

      Best Regards,

      Fotis

        • 1. Re: a4j:commandButton actionListener Facelets composition
          ilya_shaikovsky

          I would recomment dig not in RF resources. If the problem is to reference #{item} object from inside the cusomt tag - need to check the problem in passing your @component to it instead. Really easy check would be to remove and RF related code from custom tag and verify with just plan h:commandButton.

           

          B.t.w. in JSF 2 world I would prefer to wrap such stuff to composite components instead. Them are easier to create (no need to maintain any xml stuff) and more convinient to review (cc:interface section provides clean contract).

          1 of 1 people found this helpful
          • 2. Re: a4j:commandButton actionListener Facelets composition
            fotakis

            Hello Ilya,

             

            I will try to dissect your answer and see if I understood correctly.

             

            "f the problem is to reference #{item} object from inside the cusomt tag - need to check the problem in passing your @component to it instead"

             

            Here you are assuming that I did not try the same with a plain old bean, without anythign but core JSF2 and Richfaces enabled, to make sure that Spring was not doing any funky stuff behind the scene. Still the above composition would not resolve #item[saveAction] nor #item[cancelAction]

             

            "Really easy check would be to remove and RF related code from custom tag and verify with just plan h:commandButton"

             

            Yes this si a good suggestion and I will try this.

             

            "B.t.w. in JSF 2 world I would prefer to wrap such stuff to composite components instead"

             

            Can you provide some documentation on this ? Isn't this the same as separating custom components into my own facelet taglib, or are we talking about differents methods here? This sounds interesting.

             

             

            Best,

            Fotis

            • 3. Re: a4j:commandButton actionListener Facelets composition
              fotakis

              Just as a followup, using <h:commandButton> does work, which I can assume that the "item" parameter is being resolved correctly.

               

              Also I don't know if this helps debug the issue, when I set "action" instead of "actionListener" it works. Based on my litmited knowlegde "action" caused a refresh doesn't it. So there is probably something going on with the ajax part of the component.

              • 4. Re: a4j:commandButton actionListener Facelets composition
                fotakis

                Follow up #2,

                 

                You composite component mention led me to the path of enlightment , like I said I had done Facelets and JSF 1.2, which means that I was going down the taglib path, rather than composite components!

                 

                I was able to solve my problem with the following

                 

                 

                <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                <html
                    xmlns="http://www.w3.org/1999/xhtml"
                    xmlns:h="http://java.sun.com/jsf/html"
                    xmlns:composite="http://java.sun.com/jsf/composite"
                    xmlns:p="http://primefaces.prime.com.tr/ui">
                
                  <!-- INTERFACE -->
                  <composite:interface>
                    <composite:attribute name="id" type="java.lang.String"/>
                    <composite:attribute name="bean"/>
                    <composite:attribute name="width"/>
                    <composite:attribute name="update"/>
                    <composite:attribute name="saveActionListener" method-signature="void action(javax.faces.event.ActionEvent)"/>
                    <composite:attribute name="cancelActionListener" method-signature="void action(javax.faces.event.ActionEvent)"/>
                
                
                
                
                
                
                  </composite:interface>
                
                
                  <!-- IMPLEMENTATION -->          
                  <composite:implementation>
                        <p:dialog id="#{cc.attrs.id}_dialog" modal="true" widgetVar="#{cc.attrs.id}" width="#{cc.attrs.width}">
                                <h:form id="#{cc.attrs.id}_Form">
                                    <!-- The id is prepended here-->
                                    <h:panelGrid id="grid" columns="3">
                                        <composite:insertChildren></composite:insertChildren>
                
                
                                    </h:panelGrid>
                                    <h:panelGrid id="controls" columns="3">
                                    <p:commandButton
                                        id="cancelButton"
                                        immediate="true"
                                        value="Cancel"
                                        actionListener="#{cc.attrs.cancelActionListener}"
                                        oncomplete="#{cc.attrs.id}.hide()"
                                        update="@parent"/>
                                    <p:commandButton
                                        id="saveButton"
                                        value="Save"
                                        actionListener="#{cc.attrs.saveActionListener}"
                                        oncomplete="Existanze.modalPanel.canClose(xhr,status,args,#{cc.attrs.id});"
                                        update="#{cc.attrs.update}, @form"/>
                                    </h:panelGrid>
                
                
                                </h:form>
                        </p:dialog>
                  </composite:implementation>
                
                
                </html>
                
                

                 

                The rest remained the same.

                 

                For anyone passing by:

                 

                One caveat that I figured out through trial and error was to be carefull with the "Method-Signature" of the actionListeners, it must match that of your bean otherwise it wont work.

                 

                 

                Best Regards,

                Fotis