8 Replies Latest reply on Jun 14, 2007 11:54 AM by Tuncay Altun

    Problem using <a4j:outputPanel inside <h:panelGrid

    Tuncay Altun Newbie

      Hi,

      Below example using lot of <a4j:outputPanel ../> to hide/show components.

      It have a panelGrid with 3 columns. Inside the panelGrid there are 2 rows.
      First row and second row. First row seems to be ok. The main problem is in second row which is nested inside an
      <a4j:outputPanel.. meaning to process ajax response. thus is a problem using <a4j:outputPanel ../> because the second row is not alligned with first row..

      How can I allign both rows ?


      
      <h:panelGrid id="PanelGrid" columnClasses="formDescription, formValue, formError" columns="3">
      
      <!-- first row with 3 columns-->
      <h:outputLabel for="name" ../>
      <h:inputText id="name" .. />
      <t:message for="name"/>
      
      <!-- [PROBLEM!] second row should be alligned with first row ??-->
      <a4j:outputPanel id="outer">
       <a4j:outputPanel layout="none">
       <a4j:outputPanel id="inner" rendered="#{priceForm.basicPriceSelected == false}" keepTransient="true">
       <h:outputLabel for="service" ../>
       <h:panelGroup>
       <h:outputText ../>
       <f:verbatim><br/></f:verbatim>
       <h:selectManyCheckbox id="service" ..>
       <f:selectItems value="" />
       </h:selectManyCheckbox>
       </h:panelGroup>
       <t:message for="service" />
       </a4j:outputPanel>
       </a4j:outputPanel>
      </a4j:outputPanel>
      
      </h:panelGrid>
      
      


        • 1. Re: Problem using <a4j:outputPanel inside <h:panelGrid
          Sergey Smirnov Master

          It is hard for me to understand why you need so many nested outputPanels. Specially, reason for outputPanel id="outer" is not clear at all.

          • 2. Re: Problem using <a4j:outputPanel inside <h:panelGrid
            Tuncay Altun Newbie

            Hi Sergey,

            I've been spending lot of time (3 days or more) on fixing the 2 issues I have with a4j. My big team will soon use a4j only if my problems are solved.

            Ok, I enclosed the panelGrid inside the <outputPanel id="outer" and it seems to work now , but I'm not sure it's a right way. without "outer" panel it seems to not rerender the show/hide components.

            The whole code looks like following (sorry for posting all the code). Could you please check the whole code whether it is correct ? because all our team will follow this pattern if it's correct.

            <a4j:outputPanel id="outer">
            <h:panelGrid id="PanelGrid" columnClasses="formDescription, formValue, formError" columns="3">
            <h:outputLabel rendered="#{priceForm.selectedMatrixTypeId!=2}" for="provider" value="#{text['price.provider']}"/>
            <h:selectOneRadio id="provider" rendered="#{priceForm.selectedMatrixTypeId!=2}" value="#{priceForm.selectedProviderId}" required="true"
            valueChangeListener="#{priceForm.providerChanged}" immediate="true" layout="pageDirection" layoutWidth="1">
             <a4j:support event="onclick" immediate="true" reRender="service" >
             <a4j:actionparam id="priceId" value="#{priceForm.price.id}"/>
             </a4j:support>
             <f:selectItems value="#{priceForm.selectProviders}"/>
             <v:commonsValidator type="required" arg="#{text['price.provider']}"/>
            </h:selectOneRadio>
            <t:message rendered="#{priceForm.selectedMatrixTypeId!=2}" for="provider" styleClass="fieldError"/>
            
            <h:outputLabel rendered="#{priceForm.selectedMatrixTypeId==2}" for="supplier" value="#{text['price.supplier']}"/>
             <h:selectOneMenu rendered="#{priceForm.selectedMatrixTypeId==2}" id="supplier"
             value="#{priceForm.selectedSupplierId}"
             required="true"
             layout="pageDirection"
             layoutWidth="1"
             immediate="true">
             <f:selectItems value="#{priceForm.selectSuppliers}"/>
             <v:commonsValidator type="required" arg="#{text['price.supplier']}"/>
             </h:selectOneMenu>
             <t:message rendered="#{priceForm.selectedMatrixTypeId==2}" for="supplier" styleClass="fieldError"/>
            
            <h:outputLabel for="name" value="#{text['price.name']}"/>
            <h:inputText id="name" value="#{priceForm.price.name}" required="true">
             <v:commonsValidator type="required" arg="#{text['price.name']}"/>
             <f:validateLength maximum="50"/>
            </h:inputText>
            <t:message for="name"/>
            
            <h:outputLabel for="basicPrice" value="#{text['price.basicprice']}"/>
            <h:selectBooleanCheckbox id="basicPrice" value="#{priceForm.basicPriceSelected}" valueChangeListener="#{priceForm.basicPriceChanged}" immediate="true">
             <a4j:support event="onchange" immediate="true" reRender="inner,outer,inner1,inner2,dependencyTypeId"/>
            </h:selectBooleanCheckbox>
            <t:message for="basicPrice"/>
            
            <h:outputLabel for="dependencyTypeId" value="#{text['price.dependency']}"/>
            <h:panelGroup>
            <h:selectOneMenu id="dependencyTypeId"
             value="#{priceForm.price.dependencyTypeId}"
             required="true"
             valueChangeListener="#{priceForm.dependencyTypeChanged}"
             immediate="true"
             converter="viper.converter.PriceDependencyTypePavConverter">
             <a4j:support event="onchange" immediate="true" reRender="one,two,three,four"/>
             <f:selectItem itemLabel="--Select a Dependency Type --" itemValue=""/>
             <f:selectItems value="#{priceForm.selectDependencyTypes}" />
            </h:selectOneMenu>
            <br/>
            <h:outputText value="#{text['priceForm.dependency.help']}" styleClass="smallFormDescription"/>
             <t:div styleClass="smallFormDescription">
             Depended (makup/discount) price ID : <h:outputText id="one" value="#{priceForm.price.dependedActiveBasicPrice.amountInclVat}"/> <h:outputText id="two" value="#{priceForm.price.dependedActiveBasicPrice.provider.currency.name}"/>
             (Period: <h:outputText id="three" value="#{priceForm.price.dependedActiveBasicPrice.dateStart}"/> - <h:outputText id="four" value="#{priceForm.price.dependedActiveBasicPrice.dateEnd}"/> )
            </t:div>
            </h:panelGroup>
            <t:message for="dependencyTypeId"/>
            
            <h:outputLabel rendered="#{priceForm.price.dependencyTypeId==null or priceForm.price.dependencyTypeId==0 or priceForm.price.dependencyTypeId==1 or priceForm.price.dependencyTypeId==3}" for="amountExclVat" value="#{text['price.amountExclVat']}"/>
            <h:inputText rendered="#{priceForm.price.dependencyTypeId==null or priceForm.price.dependencyTypeId==0 or priceForm.price.dependencyTypeId==1 or priceForm.price.dependencyTypeId==3}" onblur="blurExclVat();" id="amountExclVat" value="#{priceForm.price.amountExclVat}" required="true">
            </h:inputText>
            <t:message for="amountExclVat"/>
            
            <h:outputLabel for="vat" value="#{text['price.vat']}"/>
            <h:inputText onblur="blurVat();" id="vat" value="#{priceForm.price.vat}">
            </h:inputText>
            <t:message for="vat"/>
            
            <h:outputLabel for="amountInclVat" value="#{text['price.amountInclVat']}"/>
            <h:inputText onblur="blurInclVat();" id="amountInclVat" value="#{priceForm.price.amountInclVat}">
            </h:inputText>
            <t:message for="amountInclVat"/>
            
            <h:outputLabel for="unitTypeId" value="#{text['price.priceunit']}"/>
            <h:selectOneMenu id="unitTypeId" value="#{priceForm.price.unitTypeId}" required="true" converter="viper.converter.PriceUnitTypePavConverter">
             <f:selectItem itemLabel="--Select a Unit Type --" itemValue=""/>
             <f:selectItems value="#{priceForm.selectUnitTypes}" />
            </h:selectOneMenu>
            <t:message for="unitTypeId"/>
            
            <h:outputLabel for="dateStart" value="Start Date"/>
            <h:panelGroup>
             <h:panelGrid columnClasses="priceDate,priceTime" columns="2">
             <tm:inputCalendar id="dateStart" value="#{priceForm.price.dateStart}" required="true">
             <v:commonsValidator type="required" arg="Start Date"/>
             <tm:dateBeforeThanValidator dateThanId="priceForm:dateEnd"/>
             </tm:inputCalendar>
             <h:outputText value="time goes here"/>
            
             <h:outputText value="#{text['priceForm.date.help']}" styleClass="smallFormDescription"/>
             <h:outputText value="#{text['priceForm.time.help']}" styleClass="smallFormDescription"/>
             <f:facet name="footer">
             <h:outputText value="#{text['priceForm.period.help']}" styleClass="smallFormDescription"/>
             </f:facet>
             </h:panelGrid>
            </h:panelGroup>
            <t:message for="dateStart" styleClass="fieldError"/>
            
            <h:outputLabel rendered="#{priceForm.basicPriceSelected==false}" for="dateEnd" value="End Date"/>
            <h:panelGroup rendered="#{priceForm.basicPriceSelected==false}">
             <h:panelGrid columnClasses="priceDate,priceTime" columns="2">
             <tm:inputCalendar id="dateEnd" value="#{priceForm.price.dateEnd}" required="true">
             <f:convertDateTime pattern="#{text['date.format']}" timeStyle="kk:mm:ss" timeZone="GMT+01"/>
             <v:commonsValidator type="required" arg="End Date"/>
             </tm:inputCalendar>
             <h:outputText value="time goes here"/>
            
             <h:outputText value="#{text['priceForm.date.help']}" styleClass="smallFormDescription"/>
             <h:outputText value="#{text['priceForm.time.help']}" styleClass="smallFormDescription"/>
             <f:facet name="footer">
             <h:outputText value="#{text['priceForm.period.help']}" styleClass="smallFormDescription"/>
             </f:facet>
             </h:panelGrid>
            </h:panelGroup>
            <t:message rendered="#{priceForm.basicPriceSelected==false}" for="dateEnd" styleClass="fieldError"/>
            
            <h:outputLabel rendered="#{priceForm.basicPriceSelected==false}" for="timeStart" value="#{text['price.hours']}"/>
            <h:panelGroup rendered="#{priceForm.basicPriceSelected==false}">
             <h:panelGrid columnClasses="priceHours,priceHoursDelimeter,priceHoursDummy" columns="3">
             <h:inputText style="width:60px;" id="timeStart" value="#{priceForm.price.timeStart}">
             <f:convertDateTime pattern="kk:mm:ss" timeZone="GMT+01"/>
             </h:inputText>
             <h:outputText value=" - "/>
             <h:inputText style="width:60px;" id="timeEnd" value="#{priceForm.price.timeEnd}">
             <f:convertDateTime pattern="kk:mm:ss" timeZone="GMT+01"/>
             </h:inputText>
            
             <h:outputText value="#{text['priceForm.hours.from.help']}" styleClass="smallFormDescription"/>
             <h:outputText />
             <h:outputText value="#{text['priceForm.hours.to.help']}" styleClass="smallFormDescription"/>
            
             <f:facet name="footer">
             <h:outputText value="#{text['priceForm.hours.help']}" styleClass="smallFormDescription"/>
             </f:facet>
             </h:panelGrid>
            </h:panelGroup>
            <t:message rendered="#{priceForm.basicPriceSelected==false}" for="dateEnd"/>
            
            <a4j:outputPanel layout="none">
             <h:outputLabel id="inner" rendered="#{priceForm.basicPriceSelected == false}" for="service" value="#{text['price.service']}"/>
            </a4j:outputPanel>
            <a4j:outputPanel layout="none">
             <h:panelGroup id="inner2" rendered="#{priceForm.basicPriceSelected == false}">
             <h:outputText value="#{text['priceForm.service.help']}" styleClass="smallFormDescription"/>
             <f:verbatim><br/></f:verbatim>
             <h:selectManyCheckbox id="service" value="#{priceForm.selectedServices}" layout="pageDirection" layoutWidth="1">
             <f:selectItems value="#{priceForm.selectServices}" />
             </h:selectManyCheckbox>
             </h:panelGroup>
            </a4j:outputPanel>
            <a4j:outputPanel layout="none">
             <t:message for="service" id="inner3" rendered="#{priceForm.basicPriceSelected == false}"/>
            </a4j:outputPanel>
            
            <h:panelGroup/>
            <h:panelGroup>
             <h:commandButton value="#{text['button.save']}" id="save" action="#{priceForm.save}" styleClass="ViperButton"/>
            
             <h:commandButton value="#{text['button.cancel']}" action="list" actionListener="#{priceForm.cancel}" immediate="true"
             id="cancel" styleClass="ViperButton" onclick="if (!confirm('#{text['popup.confirm.cancel.edit']}')) return false; bCancel=true"/>
            
            </h:panelGroup>
            </h:panelGrid>
            </a4j:outputPanel>
            


            By the way, I have another BIG BIG BIG issue in above code, I hope you can tell me why it behave like that. After rerendering a list of checkboxes with id="service" by selecting different radiobuttons id="provider" the checkboxes aren't rerendered selected?????? even if the selected values are set, why ???? I use request scope.

            Thank you very much

            • 3. Re: Problem using <a4j:outputPanel inside <h:panelGrid
              Sergey Smirnov Master

              Ok, I suggest you need to improve your understanding how Ajax4jsf works in general. Otherwise, the "copy/paste" job does not make your code optimal.

              1. you need to avoid pointing to hide/show components with reRender. It is true for now. ( see http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4052203#4052203 for details)

              2. However, you can point not only to a4j:outputPanel, but to any other jsf component that has no 'rendered' attribute. For example, you could use the id of panelGrid itself instead of wrapping it with outputpanel id="outer".

              3. Pointing to the any inner component with reRender does not make any sense if any parent component is already referenced.
              For example, reRender="inner,outer,inner1,inner2,dependencyTypeId" sounds unreasonable as soon as "outer" includes the rest items from the list.

              4. It is better to avoid reloading a huge portion of the page, like you have in the second example. You lose the benefits of the Ajax in this case

              5. Use a4j:log to monitor ajax request/responses. It will save a lot of your time to figure out what is going on with ajax communication

              • 4. Re: Problem using <a4j:outputPanel inside <h:panelGrid
                Tuncay Altun Newbie

                Hi Sergey,

                Thank you! thank you! thank you!...I'm so happy for you help. As you mention, I'm lost in understanding the whole idea behind the a4j even after reading the a4j developer guide.

                Using a4j i'm only interesting in following:
                1. hide/show some components like checkboxes
                2. depend on which radiobutton is clicked new checkboxes are loaded without checkbox selected items are disappeared when some of selected items match select items in checkbox component.

                That's only requirement I have, If I just see an example of code illustrating how to construct above requirement, I think it will give me the hole Idea about a4j, I simple don't understand region,outputpanel, etc.

                Please, can you modify the code below to match the requirement above. I will be so glad :-))


                
                <h:panelGrid id="PanelGrid" columnClasses="formDescription, formValue, formError" columns="3">
                
                 <h:outputLabel rendered="#{priceForm.selectedMatrixTypeId!=2}" for="provider" value="#{text['price.provider']}"/>
                 <h:selectOneRadio id="provider" rendered="#{priceForm.selectedMatrixTypeId!=2}" value="#{priceForm.selectedProviderId}" required="true" valueChangeListener="#{priceForm.providerChanged}" immediate="true" layout="pageDirection" layoutWidth="1">
                 <a4j:support event="onclick" immediate="true" reRender="service" >
                 <a4j:actionparam id="priceId" value="#{priceForm.price.id}"/>
                 </a4j:support>
                 <f:selectItems value="#{priceForm.selectProviders}"/>
                 <v:commonsValidator type="required" arg="#{text['price.provider']}"/>
                 </h:selectOneRadio>
                 <t:message rendered="#{priceForm.selectedMatrixTypeId!=2}" for="provider" styleClass="fieldError"/>
                
                 <h:outputLabel for="basicPrice" value="#{text['price.basicprice']}"/>
                 <h:selectBooleanCheckbox id="basicPrice" value="#{priceForm.basicPriceSelected}" valueChangeListener="#{priceForm.basicPriceChanged}" immediate="true">
                 <a4j:support event="onchange" immediate="true" reRender=""/>
                 </h:selectBooleanCheckbox>
                 <t:message for="basicPrice"/>
                
                 <h:outputLabel rendered="#{priceForm.basicPriceSelected == false}" for="service" value="#{text['price.service']}"/>
                 <h:panelGroup rendered="#{priceForm.basicPriceSelected == false}">
                 <h:outputText value="#{text['priceForm.service.help']}" styleClass="smallFormDescription"/>
                 <f:verbatim><br/></f:verbatim>
                 <h:selectManyCheckbox id="service" value="#{priceForm.selectedServices}" layout="pageDirection" layoutWidth="1">
                 <f:selectItems value="#{priceForm.selectServices}" />
                 </h:selectManyCheckbox>
                 </h:panelGroup>
                 <t:message for="service" rendered="#{priceForm.basicPriceSelected == false}"/>
                
                 <h:panelGroup/>
                 <h:panelGroup>
                 <h:commandButton value="#{text['button.save']}" id="save" action="#{priceForm.save}" styleClass="ViperButton"/>
                
                 <h:commandButton value="#{text['button.cancel']}" action="list" actionListener="#{priceForm.cancel}" immediate="true"
                 id="cancel" styleClass="ViperButton" onclick="if (!confirm('#{text['popup.confirm.cancel.edit']}')) return false; bCancel=true"/>
                 </h:panelGroup>
                
                </h:panelGrid>
                


                Thanks a lot!


                Regards

                tua


                • 5. Re: Problem using <a4j:outputPanel inside <h:panelGrid
                  Sergey Smirnov Master

                  Ajax4jsf does not change the standard JSF approaches. So, do not recognize Ajax4jsf as a magic wand - look at it like it from the JSF point of view.
                  If it is hard, add non-ajax button ( <h:commandButton value="Manual Non-Ajax Test" />) close to your a4j:support (a4j:commandLink, a4j:commandButton) and see how it work in JSF. If you have the setting for dropdown list lost, you well have the same for Ajax request - no magic

                  • 6. Re: Problem using <a4j:outputPanel inside <h:panelGrid
                    Tuncay Altun Newbie

                    Hi Sergey,

                    Thanks!

                    Regarding to your last post:

                    "4. It is better to avoid reloading a huge portion of the page ...."

                    How ?, Should I use <a4j:region ..> ajaxSingle attribute, and how ?

                    Which of two code blocks should I have a region tag enclosed with ?

                    First

                    <h:outputLabel for="basicPrice" value="#{text['price.basicprice']}"/>
                     <h:selectBooleanCheckbox
                     id="basicPrice"
                     value="#{priceForm.basicPriceSelected}"
                     valueChangeListener="#{priceForm.basicPriceChanged}"
                     immediate="true">
                     <a4j:support event="onchange" immediate="true" reRender="PanelGrid2,dependencyTypeId"/>
                     </h:selectBooleanCheckbox>
                     <t:message for="basicPrice"/>
                    



                    second
                    
                    <a4j:outputPanel layout="none" keepTransient="true">
                     <h:panelGrid id="PanelGrid2" columnClasses="formDescription, formValue, formError" columns="3">
                    
                     <h:outputLabel rendered="#{priceForm.basicPriceSelected == false}" for="service" value="#{text['price.service']}"/>
                     <h:panelGroup rendered="#{priceForm.basicPriceSelected == false}">
                     <h:outputText value="#{text['priceForm.service.help']}" styleClass="smallFormDescription"/>
                     <f:verbatim><br/></f:verbatim>
                     <h:selectManyCheckbox id="service" value="#{priceForm.selectedServices}" layout="pageDirection" layoutWidth="1">
                     <f:selectItems value="#{priceForm.selectServices}" />
                     </h:selectManyCheckbox>
                     </h:panelGroup>
                     <t:message for="service" rendered="#{priceForm.basicPriceSelected == false}"/>
                     </h:panelGrid>
                     </a4j:outputPanel>
                    


                    • 7. Re: Problem using <a4j:outputPanel inside <h:panelGrid
                      Sergey Smirnov Master

                       


                      .....
                      "4. It is better to avoid reloading a huge portion of the page"

                      How ?, Should I use <a4j:region ..> ajaxSingle attribute, and how ?


                      The answer is NO for both your guesses.
                      By "reloading" I meant the portion of html code that is transfered from a server to a client with an Ajax response.

                      a4j:region does not reduce not Ajax request nor Ajax response traffics.
                      ajaxSingle reduces Ajax request traffic, but not Ajax response one.

                      If you have small only part(s) of panelGrid is updated during ajax request/response, no reason to re-render the whole panelGrid.

                      Which of two code blocks should I have a region tag enclosed with ?


                      a4j:region limits the input fields processing by the inputs included into region. So, it is helpful when you do not want to care about values of other inputs at the same form. I.e. the whole form is still submitted, but any inputs in region make sense, the rest one are ignored.

                      • 8. Re: Problem using <a4j:outputPanel inside <h:panelGrid
                        Tuncay Altun Newbie

                        1. So below code should be valid ? And it still submits all input components but e.g. do not validates those components outside tag <a4j:region renderRegionOnly...> + ajaxSingle, I am correct ?


                        <h:outputLabel for="basicPrice" value="#{text['price.basicprice']}"/>
                        <a4j:region renderRegionOnly="false">
                        <h:selectBooleanCheckbox
                         id="basicPrice"
                         value="#{priceForm.basicPriceSelected}"
                         valueChangeListener="#{priceForm.basicPriceChanged}"
                         immediate="true">
                         <a4j:support ajaxSingle="true" event="onchange" immediate="true" reRender="PanelGrid2,dependencyTypeId"/>
                        </h:selectBooleanCheckbox>
                        </a4j:region>
                        <t:message for="basicPrice"/>