wood burning stoves 2.0*
The moose likes JSF and the fly likes Iterating over columns and rows in a data table Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Java » JSF
Bookmark "Iterating over columns and rows in a data table" Watch "Iterating over columns and rows in a data table" New topic
Author

Iterating over columns and rows in a data table

Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
To some extent I've at last figured out how to use <h:dataTable>, but I'm having problems iterating over columns and rows. In all example I've seen so far, a data table is set out so that each column has different information, such as for example a car manufacturer, car color, car year, etc. What I want to do is to have the same information in all columns and rows.

In my xhtml file I have four columns where I want to iterate over the first four columns of the first row, then the first four columns of the second row, etc., until the end of the data is reached. In this particular example there are 15 items of data, so I should have 4 rows each with 4 columns, except for the last one which should have 3. Instead I get 4 columns of 15 rows which just repeat the first column.

Here is the xhtml file:

where between each <h:column></h:column> tags the heading "User Input and Filter" is specified, followed by some spacing text, a dummy <h:input/> tag, then <h:outputText value="#{color}" escape="false"/>, where color is the iterator.

There is nothing special about choosing 4 columns, I could have chosen a different number It's a matter of making use of space in the bowser's window, Having only one column of data would not look so tidy.

The Java code is as follows:

The private method at the end works, and generates superscripts and subscripts based on the code in the string.

The xhtml code picks up the contents of the string and iterates through it, but only per column, and repeats the same for each column, so my question is how do I get the code to iterate over each row in a column, then the next row, and so on to the end? I would be very grateful for some advice on that.

At the moment I have dummy h:input tags in the xhtml code, and assuming the question above can be resolved, I would then like to sort out the code for that and read that into an array.

Many thanks for any advice.>
Volodymyr Levytskyi
Ranch Hand

Joined: Mar 29, 2012
Posts: 505
    
    1

Hello Christopher!

I really had recently very similar requirenment! And I think that it is possible to do only with ui:repeat. My ui:repeat is

h:panelGrid exists to render 6 columns in one row. Each column holds new element from profileBacking.stickers. Each element is my own class Sticker where all necessary info is stored(like 'selected=true').
About sorting: you can sort data in getter of your array or List. I found good demo at http://www.mkyong.com/jsf2/jsf-2-datatable-sorting-example/

True person is moral, false is right!
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
Hi Volodymyr,

Many thanks for your reply, and in the mean time I found a solution from:

http://javaskeleton.blogspot.fr/2011/06/generate-table-in-jsf-by-iterating-over.html

which also uses <ui:repeat>.

After making a few changes I have the following xhml code:

and made no change to the Java code. However, this uses the regular html <table> and related tags, so if I want to to stick to JSF tags as much as possible, your method may be appropriate.

Either way, the next step is to figure out how to index <h:input>, so that entry in any given input field is inserted in the correct element of an array or ArrayList.
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
I have now modified my application so that one can input data in the various fields, but I can't get it to work.

The xhtml code has been modified so that something can be entered in the <h:inputText> tags, and a button has been added at the end.

My Java code is now:

where I have added getters and setters for String[] inputs and String input, but it won't work, and I don't know how to access the individual array elements.

This must be a common problem and perhaps someone could kindly give advice.>
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
Hello,

I made a couple of changes to my xhtml file, which is now:

First I put the conditional inclusion of the </tr><tr> tags back at the top of the <ui:repeat>, where they were in http://javaskeleton.blogspot.fr/2011/06/generate-table-in-jsf-by-iterating-over.html, but added a condition preventing them from being rendered on the very first iteration. In the code from that link they were rendered the first time in the iteration, causing an empty row to be generated, which could be untidy. In my previous listing I put conditional rendering at the end, but later I realized that if the number of entries in the table is a multiple of 4, then an extra row is added at the end. This fixes that problem.

The other change was to make status.index the index for the inputs, rather than color. This at least enables the table to be displayed, but it still does not work, and I cannot see how to insert an inputted value into the correct index of the String[] inputs in my bean, which has not been changed.

If someone can help me with this, I would be very grateful, as there must be a relatively simple solution.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16095
    
  21

There's a fundamental problem with this whole idea.

JSF View definitions are NOT supposed to be programmable objects. It violates the MVC paradigm. Besides which (and more importantly), what you are really attempting to do isn't "iterate", you are looking to construct a 2-dimensional object in the View. Iteration is only one of several ways to do that (especially if you have parallel processing capabilities). Why hard-code a specific solution into a problem if you don't have to?

I didn't follow everything in detail, but if all of the cells in a table are identical, the tag that does this without explicit iteration is the "dataGrid" control.


Customer surveys are for companies who didn't pay proper attention to begin with.
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
Hi Tim,

I'm aware that what I'm doing is rendering a 2D view, and was only using the word "iteration" rather loosely. I have more than 30 sets of strings of various lengths which will be read in from a file, but to test out the code I hard-coded one example to keep the code short.

Basically I have an array of strings that is displayed in the table and label each input box, in this particular case 15, and I also have a matching array of empty strings that is supposed to be filled up when you enter a value in each of the boxes below each label. The idea is that when you enter something in one of the boxes, JSF knows which index of the array of input strings to place the value. For example, if you enter something in the first input on the upper left, something is supposed to be inserted into the zeroth index of the array, when something is inserted into the next box on the right, this is supposed to go to the first indexs of the array, and so on. The indices run 0, 1, 2, 3, etc. from left to right in the first row, then so on in the following rows.

Incidentally, I just changed the number of columns per row from 4 to 5, as this looks a bit better, but does not change otherwise anything.
Volodymyr Levytskyi
Ranch Hand

Joined: Mar 29, 2012
Posts: 505
    
    1

Hello!

I would recommend to use your own class that holds all data for one iteration. You will never have problems with binding ui components to needed object.


I don't know other way to iterate through array of objects in jsf except <h:dataTable> and <ui:repeat>
<h:dataTable> processes one iteration for one row.

Can anybody tell how to process one iteration for one column in jsf except <ui:repeat>? I merely need to bind one object to one column
with iteration because there are near 30 such objects and each binds to concrete group of ui components (label, checkbox, image).



Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
Judging by what I've found on Google, it looks as if I have to use the interface DataModel with the class ArrayDataModel. I've imported the relevant classes, and have in my class:

But I'm still unable to get my code to work.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16095
    
  21

Primitive classes don't work well as TableModels because they have no properties and you need a property name in order to access the data.

Here's something more appropriate. It probably does not work "as is", but it might help things make sense when you RTFM.

First, the display template:



No "repeat" tags required.

Now the class object that myModel is based on:



To construct the actual model, instantiate an array or List of MyModelCell and initialize the captions and initial values. Then wrap that array in a DataModel (ArrayDataModel or ListDataModel).

Note that although you are displaying a 2-dimensional grid, we are modelling it in a 1-dimensional collection. Java isn't a big fan of multi-dimensional arrays, But since this is only the UI model, it doesn't matter. Translate as needed.
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
Hi Tim,

OK, many thanks, and this is what I've got now for the xhtml file:

and for the bean I have this:

but it still does not work. Eclipse complains that "filterCell" in the input tag in the xhtml file cannot be resolved, and when I run the code I get just one input box displayed, and nothing else.

There is some redundant code in the bean that can be cleaned up, but that cannot be the reason why it's not working.

I created the inner class MyFilterCell, the constructed it "num" times in a loop with the String arrays colors[] and userInputs[], then wrapped these in an
ArrayDataModel.

Any ideas???
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16095
    
  21

You don't seem to have gotten the enumeration concept quite right. The "var" is your "loop variable", and thus "item" would be the cell model instance. So a construct like


would be questionable at best, since you're referring the the model object and not one of its properties. Look at my example.

Conversely


wouldn't be proper if "item" was an instance of MyFilterCell for the same reason, albeit going too far in the other direction.
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
Hi Tim,

So that is where I am confused, when var="item" in a data table or in a <ui:repeat>, "item" is not an index, but is an instance that is being iterated over. The actual index is given by status.index, when varStatus="status". Please correct me if I am wrong on that.

Anyway, I've rewritten my application from scratch, and I'm still having problems.

Here is the xhtml code:

I've put me previous inner class in a separate file, and it is now:

and the bean is here:

As far as I can see, I've done everything correctly, but obviously I have not, as it does not render anything. In putting some test print statements in, it fails the first time it goes round the second loop in the constructor MyFilterBean(). When filterCells[i] = new FilterCell(colors[i], "" + i) is called with i=0, the constructor FilterCel() is called and the two strings are passed, but then it fails, and will not work for i=1.

The second string will be a blank that the user can change with the h:inputText, but for test purposes I put a number in there.

Could you or someone else help me get this sorted out, as I would be most grateful.>
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
In fact I just noticed an error, the method in the last listing "public void setFilterCell" should be "public void setFilterCells". I fixed that but it still fails the same way as before.
Volodymyr Levytskyi
Ranch Hand

Joined: Mar 29, 2012
Posts: 505
    
    1

Hello!

You should generate getters and setters by IDE.

I am not sure but I have not met anywhere else this - ><. And this is in your constructor. But you could generate 'for' loop with Eclipse as well.
Apparanly this is mistake that must be detected by IDE.
How didn't you notice this?
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16095
    
  21

I think you have confused "loop index" with what in mathematical terms would be "subscript".

When you say in Java: foreach (x in collectionofx), the index is "x". As the iteration progresses, first collectionofx[0] is presented as x, then collectionpofx[1], and so forth. So the "var" in a ui:repeat, h:datagrid, or h:datatable whose model was a collection of FilterCell would be a series of FilterCell instances, and not the numeric array index of the collection.
Volodymyr Levytskyi
Ranch Hand

Joined: Mar 29, 2012
Posts: 505
    
    1

Sorry if I don't understand something but what is h:datagrid.
I use JSF 2.1 and I don't see such element. I see only h:panelGrid but it does not have either var or value attributes.

What is h:datagrid?
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
OK, at last I got it fixed, I omitted a statement in my constructor indicated here:

The code now works, and I can input values in the xhtml file, which is unchanged, except that I put back in the command button.

In my action method I can go in a loop and see the values that have been inputted. Presumably it should be possible to use an ArrayDataModel to find out which value(s) have been changed without going through a loop, but that will have to wait for another day. After having put Ajax on the back burner, I will have to get back to it.

Volodymyr: As to h:dataGrid, as far as I know it does not exist, but p:dataGrid, as in PrimeFaces, does exist. I've started looking at PrimeFaces with a view of using some of its features, but it's taking me much longer than expected getting familiar regular JSF 2.0.

Tim: Thanks for clarifying indices.
>
Christopher Sharp
Ranch Hand

Joined: Dec 12, 2007
Posts: 154
Hi Tim,

As I got the code to work using the ui:repeat tags with the table tags, I tried your method of using h:panelGrid which you posted a few days earlier. Here is my code with the relevant changes:

It fails. a single input field shows up, and when I click the button to fire the action, it fails completely.

As far as I know h:panelGrid cannot be used this way at all. If someone knows otherwise, I would be interested to know, and in the mean time I will just use the code I know works.

Yes, I know, one should use JSF tags and avoid html tags as much as possible, but apparently this is one of those situations where there is no alternative, unless one is going to use PrimeFaces, RichFaces, or IceFaces, and PrimeFaces is one of the frameworks I've started looking at.
Tim Holloway
Saloon Keeper

Joined: Jun 25, 2001
Posts: 16095
    
  21

Don't use actionListener. ActionListeners are cumbersome and non-portable, unlike actions, which are much simpler POJO methods. In fact, the reason for failure may very well have been that you coded the method like an action method but your View Definition is for an action listener, which has an entirely different method signature.

ActionListeners have their uses, but 95% of the time, they're not necessary.
 
GeeCON Prague 2014
 
subject: Iterating over columns and rows in a data table