4 Replies Latest reply on Jun 28, 2013 12:42 PM by incubator01

    RichFaces UI structure and pittfalls

    incubator01

      Hi,

       

      I am new to RF and am having difficulties with making a simple CRUD project in this framework.

      What the end user essentially wants is a simple table with the ability to select a row, when this happens the action buttons on the left of this table change (enable/disable)

      So for example when one would press the "Add item" a popupPanel would appear with a small form with just 2 text fields, a save and cancel button.

       

      The problems I currently face are:

      - Sometimes the action of the save button in said popupPanel is not triggered, on other occasions, like when first submitting an empty form and then a filled one, it does work.

      - When triggering a create/update or delete of an item I ask the table to be re-rendered, this does not happen however and in order to see the updated list I must refresh the page.

      - The extendedDataTable's column widths are ignoring percentages, using <rich:column width="100%"> does nothing and seems similar to auito, while <rich:column width="400px" scales it properly to 400 pixels. using CSS classes does not change anything, so is there a way to have percentage based column widths for chaning resolutions?

      - In my code I now have one form which surrounds both my action buttons and my table, and another form which surrounds my popupPanel. Is this a wise decision or should I do it differently? I ended up this way since splitting it up made it even worse both in layout and behaviour.

      - As I am used to different platforms than JSF I was also wondering if the general approach to my code is a good strategy or how I should do this otherwise.

      - Notice the render attributes for the commandButton action bar, I set it to @form out of desperation but nothing there seems to work. Does the render occur before or after the action or am i simply using the wrong type?

       

      Below is my index.xhtml:

       

      <?xml version="1.0" encoding="UTF-8"?>
      <!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:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:ui="http://java.sun.com/jsf/facelets"
          xmlns:rich="http://richfaces.org/rich"
          xmlns:a4j="http://richfaces.org/a4j">
      <!-- head omitted for clarity -->
      <h:body>    
                  <h:form>
                  <h:panelGrid columns="2" columnClasses="menuColumn,contentColumn"
                      height="100%" width="90%">
      
                     <!-- Action button bar -->
                      <h:panelGrid columns="1" columnClasses="cols" height="100%"
                          width="24">
                          <a4j:commandButton type="image" image="/resources/img/page_add.png" 
                              execute="@form" render="edit_form" action="#{liveCycleProxyController.addMapping}"
                              oncomplete="#{rich:component('popup')}.show();">
                              <rich:tooltip value="#{rs['controls.add']}" for="btnAdd" />
                          </a4j:commandButton>
                          
                          <a4j:commandButton type="image" image="/resources/img/page_white_edit.png" 
                              execute="@form" render="edit_form" action="#{liveCycleProxyController.updateMapping}"
                              oncomplete="#{rich:component('popup')}.show();">
                              <rich:tooltip value="#{rs['controls.update']}" for="btnUpdate" />
                          </a4j:commandButton>
                          
                          
                          <a4j:commandButton type="image" image="/resources/img/delete.png" 
                              execute="@form" render="@form"
                              action="#{liveCycleProxyController.removeMapping}">
                              <rich:tooltip value="#{rs['controls.delete']}" for="btnDelete" />
                          </a4j:commandButton>
                      </h:panelGrid>
      
                      <rich:extendedDataTable var="mapping" id="mappingTable"
                          noDataLabel="#{rs.noItemsFound}" selectionMode="single"
                          selection="#{liveCycleProxyController.selection}"
                          value="#{liveCycleProxyController.mappings}">
                          <a4j:ajax execute="@form" event="selectionchange" 
                              listener="#{liveCycleProxyController.selectionListener}"/>
                          <f:facet name="header">
                              <h:outputText value="#{rs.mappingTableHeader}" />
                          </f:facet>
                          <rich:column width="300px">
                              <f:facet name="header">
                                  <h:outputText value="#{rs.keyColumnHeader}" />
                              </f:facet>
                              <h:outputText value="#{mapping.mappingName}" />
                          </rich:column>
                          <rich:column width="300px">
                              <f:facet name="header">
                                  <h:outputText value="#{rs.valueColumnHeader}" />
                              </f:facet>
                              <h:outputText value="#{mapping.url}" />
                          </rich:column>
                      </rich:extendedDataTable>
                  </h:panelGrid>
                  </h:form>
      
                  <!-- Mapping popup -->
                  <a4j:region>
                  <h:form id="edit_form">
                      <rich:popupPanel id="popup" modal="true" autosized="true"
                          resizeable="false" domElementAttachment="form" >
                          <f:facet name="header">
                              <h:outputText value="#{rs.mappingData}" />
                          </f:facet>
                              <h:inputHidden name="id"
                                  value="#{liveCycleProxyController.id}" />
          
                              <h:outputLabel value="#{rs.keyColumnHeader}: " for="txtName" />                      
          
                              <h:inputText id="txtName"
                                  value="#{liveCycleProxyController.mappingName}" />
                              <h:message for="txtName"/>
                              <br />
          
                              <h:outputLabel value="#{rs.valueColumnHeader}: " for="txtUrl" />                        
          
                              <h:inputText id="txtUrl"
                                  value="#{liveCycleProxyController.url}" />
                              <h:message for="txtUrl"/>
                              <br />
                              
                              <p class="submit">
                                  <a4j:commandButton id="save" value="Save"
                                      render="mappingTable"
                                      action="#{liveCycleProxyController.save}" type="submit"
                                      oncomplete="#{rich:component('popup')}.hide(); "
                                      />
          
                                  <a4j:commandButton id="cancel" value="Cancel"
                                      action="#{liveCycleProxyController.cancel}" ajaxSingle="true"
                                      immediate="true" oncomplete="#{rich:component('popup')}.hide(); " />
                              </p>    
                      </rich:popupPanel>
                  </h:form>
                  </a4j:region>
      </h:body>
      </html>
      

       

      and in attachment the included Java Bean,

       

      If anyone is able to point me in the right direction I would very much appreciate this.

      If what I want to do with RF is impossible (I worked with Flex and ExtJS before) then that would be a sad thing, given all the Ajax functionality being present.

      But the examples that are present in the showcase are very limited in showing me a proper way of how to work with the framework, so that's why I need more help to find my way

       

      Thanks in advance!

        • 1. Re: RichFaces UI structure and pittfalls
          bleathem

          I think the problem is that your a4j:commandButton is has as a render target an adjacent form.  This is likely giving you problems with a stale ViewState in the 2nd form.  Try doing this all in a single form, and see if that resolves your problems.  If it does, we can look more closely at how you can achieve the expected behaviour with multiple forms.

           

          Further reading:

          http://www.irian.at/en/blog/-/blogs/jsf-ajax-and-multiple-forms

          1 of 1 people found this helpful
          • 2. Re: RichFaces UI structure and pittfalls
            incubator01

            Hi,

             

            This seemed to be indeed part of the problem. Now I can open the popup, submit it, bean validation also works, record is added, but the table is not refreshed via ajax.

            Also the bean validation already triggers upon opening the popup, preferrably this should be triggered on submit.

             

            As a sidenote, how can I debug my Java code? I am unable to open a remote socket in eclipse to JBoss 7.1.1 to debug CDI beans while I am perfectly able to debug for example a spring framework backend, I keep getting an error that eclipse was unable to attach a listener to the proxy class from Weld. (I use CDI)

             

            I updated my page as follows:

             

             

                        <h:form>
                        <h:panelGrid columns="2" columnClasses="menuColumn,contentColumn"
                            height="100%" width="90%">
                            <h:panelGrid columns="1" columnClasses="cols" height="100%"
                                width="24">
                                <a4j:commandButton type="image" image="/resources/img/page_add.png" 
                                    execute="@form" render="popup" action="#{liveCycleProxyController.addMapping}"
                                    oncomplete="#{rich:component('popup')}.show();">
                                    <rich:tooltip value="#{rs['controls.add']}" for="btnAdd" />
                                </a4j:commandButton>
                                
                                <a4j:commandButton type="image" image="/resources/img/page_white_edit.png" 
                                    execute="@form" render="popup" action="#{liveCycleProxyController.updateMapping}"
                                    oncomplete="#{rich:component('popup')}.show();">
                                    <rich:tooltip value="#{rs['controls.update']}" for="btnUpdate" />
                                </a4j:commandButton>
                                
                                
                                <a4j:commandButton type="image" image="/resources/img/delete.png" 
                                    execute="@form" render="@form" <!-- ignore this block for now -->
                                    action="#{liveCycleProxyController.removeMapping}">
                                    <rich:tooltip value="#{rs['controls.delete']}" for="btnDelete" />
                                </a4j:commandButton>
                            </h:panelGrid>
            
                            <rich:extendedDataTable var="mapping" id="mappingTable"
                                noDataLabel="#{rs.noItemsFound}" selectionMode="single"
                                selection="#{liveCycleProxyController.selection}"
                                value="#{liveCycleProxyController.mappings}">
                                <a4j:ajax execute="@form" event="selectionchange" 
                                    listener="#{liveCycleProxyController.selectionListener}"/>
                                <f:facet name="header">
                                    <h:outputText value="#{rs.mappingTableHeader}" />
                                </f:facet>
                                <rich:column width="300px">
                                    <f:facet name="header">
                                        <h:outputText value="#{rs.keyColumnHeader}" />
                                    </f:facet>
                                    <h:outputText value="#{mapping.mappingName}" />
                                </rich:column>
                                <rich:column width="300px">
                                    <f:facet name="header">
                                        <h:outputText value="#{rs.valueColumnHeader}" />
                                    </f:facet>
                                    <h:outputText value="#{mapping.url}" />
                                </rich:column>
                            </rich:extendedDataTable>
                        </h:panelGrid>
            
                        <!-- Mapping popup -->
                        <a4j:region>
                            <rich:popupPanel id="popup" modal="true" autosized="true"
                                resizeable="false" domElementAttachment="form" >
                                <f:facet name="header">
                                    <h:outputText value="#{rs.mappingData}" />
                                </f:facet>
                                    <h:inputHidden name="id"
                                        value="#{liveCycleProxyController.id}" />
                
                                    <h:outputLabel value="#{rs.keyColumnHeader}: " for="txtName" />  
               
                                    <h:inputText id="txtName"
                                        value="#{liveCycleProxyController.mappingName}" />
                                    <h:message for="txtName"/>
                                    <br />
                
                                    <h:outputLabel value="#{rs.valueColumnHeader}: " for="txtUrl" />     
                
                                    <h:inputText id="txtUrl"
                                        value="#{liveCycleProxyController.url}" />
                                    <h:message for="txtUrl"/>
                                    <br />
                                    
                                    <!-- the actions ... -->
                                    <p class="submit">
                                        <a4j:commandButton id="save" value="Save"
                                            render="mappingTable"
                                            action="#{liveCycleProxyController.save}" type="submit"
                                            oncomplete="#{rich:component('popup')}.hide(); "
                                            />
                
                                        <a4j:commandButton id="cancel" value="Cancel"
                                            action="#{liveCycleProxyController.cancel}" ajaxSingle="true"
                                            immediate="true" oncomplete="#{rich:component('popup')}.hide(); " />
                                    </p>
                            </rich:popupPanel>
                        </a4j:region>
                        </h:form>
            
            

             

             

            The parts in bold is what I changed.

            • 3. Re: RichFaces UI structure and pittfalls
              bleathem

              Bean validation is being triggered because you are executing the whole form.  Valildation is triggered when you execute a component.

               

              As for debugging, you should have no trouble debugging a CDI application, I do it all the time.  What's your setup?

              • 4. Re: RichFaces UI structure and pittfalls
                incubator01

                I use Eclipse 4.2 and JBoss AS 7.1.1, when trying to initiate socket debug connection on port 8787 I received an error that adding a listener to the proxy of my CDI bean failed.

                However, the next day this error dissappeared.

                 

                In the end I managed to solve most of my errors, my command buttons' execute for the actions should have been @this and not @form, I needed rich:outputPanel with ajaxRendered="true" around that popup and around the table and buttons.

                The only thing that bothers me is the inability to use percentage widths in columns in the extendedDataTable (there are JIRA issues for this, moved to RF 5) and that pressing enter while having a textfield focused in the popup causes teh popup to be rerendered in initial state, not in validated state.