14 Replies Latest reply on Jun 30, 2011 2:19 AM by itnilesh

    Solution for ui:repeat with varStatus and new parameters "from" and "to"

    rehdie

      Since I needed a varStatus for ui:repeat, I've create my own version of the ui:repeat tag, which has the following new features:


      It now supports the attribute varStatus. The status object has the following attributes:




      • index: the current - zero based - index

      • count: the number of iterations. If the count is not available (e.g. for variables of type ResultSet): -1

      • last:  true, if the current iteration is the last one

      • first: true, if the current iteration is the first one

      • from, to: for simple for-loops without a collection



      example 1:


      <ui:repeat value="#{myCollection}" var="item"  varStatus="status">
      
         <h:outputText value="...."  rendered="#{status.first}"/>
         <h:outputText value="...."  rendered="#{status.index gt 5}"/>
         .......
      </ui:repeat>
      



      example 2:


      <ui:repeat var="i" varStatus="status" from="5" to="7">
         value: #{i}<br/>
         index: #{status.index}<br/>
      </ui:repeat>
      



      The second example renders the following output:


      value: 5
      index: 0
      value: 6
      index: 1
      value: 7
      index: 2



      The sourcecode for the new version of the class UIRepeat can be downloaded from here (unfortunately this forum does not support file uploads).



      To use it, you have to add a new entry to the file WEB-INF/faces-config.xml:


      <?xml version='1.0' encoding='UTF-8'?>
      <faces-config version="1.2"
                    xmlns="http://java.sun.com/xml/ns/javaee"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
      
         <!-- this component entry is new: -->
         <component>
              <component-type>facelets.ui.Repeat</component-type>
              <component-class>com.alturos.gui.facelets.UIRepeat</component-class>
          </component>
          
         <application>
            <locale-config>
               <default-locale>de</default-locale>
               <supported-locale>cs</supported-locale>
               <supported-locale>de</supported-locale>
               <supported-locale>en</supported-locale>
               <supported-locale>fr</supported-locale>
               <supported-locale>it</supported-locale>
               <supported-locale>ru</supported-locale>
            </locale-config>
            <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
         </application>
      
      </faces-config>
      




        • 1. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
          rehdie

          sorry, there are some mistakes in the previous post:


          the status object provides the following attributes:



          • index

          • count

          • last

          • first



          The tag has the following new attributes:



          • from

          • to



          The attribute varStatus already existed but it was not used by the original UIRepeat version.

          • 2. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
            kirill1977

            hi, thanks for this solution


            but in your class exist a little mistake  (i found at least one)
            your code



               private synchronized DataModel getDataModel()
               {
                  if(this.model == null)
                  {
                        ...
                  }
                  status = new Status(model.getRowCount());
                  return this.model;
               }
            



            should be


               private synchronized DataModel getDataModel()
               {
                  if(this.model == null)
                  {
                        ...
                        status = new Status(model.getRowCount());
                  }
                  return this.model;
               }
            


            otherwise varStatus.index doesn't work

            • 3. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"

              Hi,


              i would also need a varStatus attribute.


              Dieter, i've tried your solution and could not get it work.
              The status.index stays empty.


              have you already used your Tag in you projects? May be you have already a fixed vertion. Or a tip how to get it work.


              The Tag would be very usefull.


              thanks a lot
              regards

              • 4. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                palacete

                Worked fine for me. Thanks a lot Dieter!

                • 5. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                  sancar

                  Kirill Kudriavtsev is right, you need to move the line


                            status = new Status(model.getRowCount());
                  



                  one line up into the if-clause.
                  Thanks anyhow, just what I needed.

                  • 6. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                    magnus

                    Worked excellent for my needs, with the patch suggested by Sancar. Used it to display , between elements excluding the last one. Thanks!

                    • 7. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                      flopsi
                      Hi everybody,
                      i configured the new version as stated but it seems that it is switched to the original ui:repeat version sometimes.

                      I use it in a search results page to distiguish the rows by evaluating varStatus.index. In this page there is a combo to select the results per page.

                      Everything works fine (e.g. paging) as long as i do not use the box. If i use it, the correct results are displayed, but all rows have the same color, which is the same effect as if i used the original ui:repeat that does not know varStatus.
                      Maybe the problem is the postback that the box does?!? But what is the solution? Page parameters are properly configured in corresponding pages.xml...

                      Every help is greatly appreciated,
                      thanks + best regards
                      Flo
                      • 8. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                        elnino

                        Hello,


                        I have found your UIRepeat patch and I am really excited because it will solv one of my big problem. Thanks for the job !


                        But, I have a problem. Taking your code I have a problem with two import:



                        import com.sun.facelets.tag.jsf.ComponentSupport;
                        import com.sun.facelets.util.FacesAPI;




                        So I look on Seam lib, and I had jsf-facelets.jar and jsf-impl.jar  in my EAR updating the class-path in the MANIFEST. It's compile well but when I launch the app, I have an exception:




                        Can't find resource for bundle java.util.PropertyResourceBundle, key el.convert





                        I 'am using JBOSS AS 5.


                        I think I have some jar incompatibilities between SEAM jar and JBoss Jar.
                        Can you list the Jar you used and where you put them ?

                        • 9. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                          flagster

                          If (like me) you don't have the luxury of modifying the Java-backing code that your facelet is working against, here's a workaround that helped me through what I was doing with ui:repeat - trying to comma-separate a list but omitting the comma after the final/last item.


                          Assume we have no varStatus:


                          <ui:repeat value="#{myCollection}" var="item">
                             <!-- want to output the comma-separated list of items here -->
                          </ui:repeat>



                          You can use the rendered= attribute of h:outputText and compare the array metadata:


                          <ui:repeat value="#{myCollection}" var="item">
                             #{item}
                             <h:outputText value=", " rendered="#{myCollection.indexOf(item) &lt; (myCollection.size - 1)}" />
                          </ui:repeat>



                          Why the [size-1]?  The .indexOf() call returns a 0-based value, ie the first item in your array is effectively myCollection[0], but the .size count starts at 1.


                          As a novice SEAM/facelet developer, I'm uncertain how expensive these operations are - make sure you have a way to profile performance of this code in your application before deciding it's the way to go - but if you're stuck in an implementation of facelets where varStatus isn't available, knowing that you can use .indexOf and .size as part of a rendered= condition within <ui:repeat> might just help you out of a jam.

                          • 10. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                            stuartc

                            @Flo,


                            You are correct: the component state is not completely restored on postback. Specifically, the varStatus attribute value is not saved or restored.


                            Here are the saveState/restoreState method changes I made, which seem to work:


                                public void restoreState(FacesContext faces, Object object) {
                                    Object[] state = (Object[]) object;
                                    super.restoreState(faces, state[0]);
                                    this.childState = (Map) state[1];
                                    this.offset = ((Integer) state[2]).intValue();
                                    this.size = ((Integer) state[3]).intValue();
                                    this.var = (String) state[4];
                                    this.varStatus = (String) state[5];
                                    this.value = state[6];
                                }
                            
                                public Object saveState(FacesContext faces) {
                                    return new Object[] {
                                        super.saveState(faces),
                                        this.childState,
                                        new Integer(this.offset),
                                        new Integer(this.size),
                                        this.var,
                                        this.varStatus,
                                        this.value
                                    };
                                }
                            



                            Dieter - thanks for the solution!

                            • 11. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                              almeidap

                              Hi Dieter, thanks for your implementation of varStatus!


                              I was also interested in using the from and to attributes but it seems that your component is only expecting Number types and my JSF environment provides String values, e.g.:



                              private int getFromValue() {
                                   ...
                                   if (from instanceof Number) {
                                        return ((Number) from).intValue();
                                   } else {
                                        return 0;
                                   }
                                   ...
                              }



                              So, I simply changed your getFromValue() and getToValue() methods like this:




                                   private int getFromValue() {
                                        Object from = this.from;
                              
                                        if (from == null) {
                                             ValueBinding vb = this.getValueBinding("from");
                                             if (vb != null) {
                                                  from = vb.getValue(FacesContext.getCurrentInstance());
                                             }
                                        }
                              
                                        if (from instanceof Number) {
                                             return ((Number) from).intValue();
                                        } else {
                                             return 0;
                                        }
                                   }
                              
                                   private int getToValue() {
                                        Object to = this.to;
                              
                                        if (to == null) {
                                             ValueBinding vb = this.getValueBinding("to");
                                             if (vb != null) {
                                                  to = vb.getValue(FacesContext.getCurrentInstance());
                                             }
                                        }
                              
                                        if (to instanceof Number) {
                                             return ((Number) to).intValue();
                                        } else if (to instanceof String) {
                                             return Integer.valueOf(((String) to));
                                        } else {
                                             return -1;
                                        }
                                   }


                              And it works nice now! Hope this will be helpfull to others... ;)

                              • 12. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                                almeidap

                                Sorry, the method getFromValue() should be in fact:


                                     private int getFromValue() {
                                          Object from = this.from;
                                
                                          if (from == null) {
                                               ValueBinding vb = this.getValueBinding("from");
                                               if (vb != null) {
                                                    from = vb.getValue(FacesContext.getCurrentInstance());
                                               }
                                          }
                                
                                          if (from instanceof Number) {
                                               return ((Number) from).intValue();
                                          } else if (from instanceof String) {
                                               return Integer.valueOf(((String) from));
                                          } else {
                                               return 0;
                                          }
                                     }



                                • 13. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                                  itnilesh
                                  Kirill Kudriavtsev is right, you need to move the line
                                  Because of that error index gives only two values
                                  exp -  if there are 8 elements in list

                                  value of index -

                                  0,1,1,1,1,1,1,,1

                                  After moving that code inside if block

                                  status = new Status(model.getRowCount());


                                  it was like

                                  value of index

                                  0,1,2,3,4,5,6,7

                                  Please move that code inside . :)

                                  • 14. Re: Solution for ui:repeat with varStatus and new parameters "from" and "to"
                                    itnilesh

                                    Still this component has problem if we AJAX re-render in rich faces prime faces .


                                    Because problem with restore and save state methods .


                                    FYI - people using JSF 2.0 have var status component in built so do not waste time here .



                                    Please replace methods with




                                      


                                    public void restoreState(FacesContext faces, Object object)
                                       {
                                          Object[] state = (Object[])object;
                                          super.restoreState(faces, state[0]);
                                          this.childState = (Map)state[1];
                                          this.offset = ((Integer)state[2]).intValue();
                                          this.size = ((Integer)state[3]).intValue();
                                          this.var = (String)state[4];
                                          this.value = state[5];
                                          this.varStatus= (String)state[6];
                                       }
                                    
                                    
                                    
                                    
                                      public Object saveState(FacesContext faces)
                                       {
                                          Object[] state = new Object[7];
                                          state[0] = super.saveState(faces);
                                          state[1] = this.childState;
                                          state[2] = new Integer(this.offset);
                                          state[3] = new Integer(this.size);
                                          state[4] = this.var;
                                          state[5] = this.value;
                                          state[6] = this.varStatus;
                                          return state;
                                       }