This week's book giveaway is in the Kotlin forum.
We're giving away four copies of Kotlin in Action and have Dmitry Jemerov & Svetlana Isakova on-line!
See this thread for details.
Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Primefaces columnIndexVar not updating on first backing bean method call  RSS feed

 
Nathan Shields
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I've been working on dynamically generating tables (number of rows and columns are dynamic) from a RESTful GET, and it's almost there. The only problem (that I can see now, hehe) is that "columnIndexVar" appears to be updated AFTER the table itself is drawn. Here's my code, followed by an example:
HTML


JAVA (abridged to remove sensitive and irrelevant code)



encryptedBase64String comes from responseString, and displayBoardNum comes from the argument in action="#{decryptionBean.loadBoard(0)}". The data is parsed correctly, as the tables render with the correct information after "...loadboard0" is clicked a second time.

Example of the problem:
displayBoardArray[0].displayData is a 2x2 array by default:
- -
- -
Send a GET request to get data in a 3x3 array:
1 2 3
1 2 3
1 2 3
Datatable renders as:
1 2
1 2
1 2
Send GET request a second time, result is:
1 2 3
1 2 3
1 2 3

The number of rows, as well as the data is correct, but the size of columns isn't. I believe this is because columnIndexVar is being changed after the function has run, although I have no idea how to fix it. I tried adding a Thread.sleep(5000) at the end of loadBoard(int), but that didn't help. I also tried setting columnIndexVar as equal to numCols (which is used inside the function), and that only succeeded in preventing all output.

Any idea what's going on and/or how I can fix it?
 
Tim Holloway
Bartender
Posts: 18709
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Welcome to the JavaRanch, Nathan!

That's a bit more than I can make sense of this early in the morning, but I do have some observations.

First, you shouldn't pass parameters on your action definition. It may or may not work, depending on what version of JSF you are using, but EL is essentially a declaration language, not a programming language and action methods aren't supposed to be parameterized. They obtain their data directly from the backing bean.

The other observation I'm going to make is a bit fuzzier. JSF displays tables as 2-dimensional objects. As far as the page display is concerned, each row and column in the table was generated via parallel processing simultaneously and the whole table popped into view at once. While in a specific implementation looping may be part of the internal process, you should not code like it is.

Also, just to highlight some common concerns, a dataTable's "value" object should not be a raw data source or collection. It should be an instance of javax.faces.DataModel. The DataModel wraps the actual data and decorates it with stuff that aids in both rendering the table for display and determining which row of a table you have selected when you submit an action based on a row in the table. The DataModel cannot be Request-scoped, as otherwise that information is lost when the client acts on the displayed table (a whole new model is constructed, lacking the previous context).

When assembling the dataModel, don't construct it - or the underlying data - on every "get" of the model. The overhead can be significant, and if there are side-effects, they will make like difficult.
 
Nathan Shields
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Tim! Thanks for the warm welcome :) Sorry to make you go 0-60 right after you got up!

First, you shouldn't pass parameters on your action definition


Fixed that one! I was trying to avoid rewriting code even if it was just loadBoard0() and loadBoard1(), but so it goes.

As for the DataModel... that's a whole 'nother beast for me. I did a bit of googling around, and it looks appears that ListDataModel is what I'm probably looking for. The problem: it appears to only work when the list is holding the objects that have to be displayed. That'd be great, but my lists ARE the "objects" that I want to display, and they don't have member variables. I'm nearly certain I can't replace my List<String> with



because I don't know how many columns there are going to be. I tried to get around this by sneakily throwing List<String>s into a List<ListDataModel>:



dataArray has getters and setters.

However I recieved an exception:
java.lang.IndexOutOfBoundsException: at andon_board.DecryptionBean.parseBoardData(DecryptionBean.java:543): Index: 0, Size: 0

543 is the line above inside the for above loop. I thought I initialized the dataArray to size 10, but maybe I did something wrong there?
Oh, and here's my JSF: The page loads and everything, it just fails (nothing happens, aside for the stack trace printing in the console) when I try to load the data.


Those are the changes I made to the JSF to try to get it to work with the ListDataModel.

I guess I'm just completely befuddled when it comes to using DataModel, seeing as it wants objects/classes with member variables and I don't have any. Actually, it appears DataTable itself thrives on objects, which is probably part of the reason this is proving dificult for me.
Any ideas about where to go from here? Thanks for the help you've given me so far!

 
Tim Holloway
Bartender
Posts: 18709
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'd have to check, but I think a simple list of Strings can be displayed in a 1-column table like so:


For a table based on a list of lists of strings, it would be more like:
<h:dataTable var="row" value="#{myBean.strings}">
<h:column><h:outputText value="#{row[0]}"/></h:column>
<h:column><h:outputText value="#{row[1]}"/></h:column>
<h:column><h:outputText value="#{row[2]}"/></h:column>
</h:dataTable>

I'm not well-versed in PrimeFaces, but I do know that RichFaces has a type of table where the number of columns is adjustable and a column index is available.
 
Nathan Shields
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So... I switched it all over to ArrayList<ListDataModel<List<String>>>>, got all the information displaying correctly, but the exact same bug still persists.
It seems like the amount of columns is the problem, which corresponds to the size of the rows, aka ArrayList.size(), so I'm going to try to do the following:

:(
I'll get back to you guys when that's said and done, hopefully with a tale of success.
 
Tim Holloway
Bartender
Posts: 18709
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I can't speak for PrimeFaces, but the RichFaces equivalent didn't use a DataModel for columns. There's a trick to what they did, but I believe that the column models objects were ordinary list elements. Something like:


Where "ColumnModel" was the object class for the items within a column.

I do know that JSF does not do a very good job of supporting nested DataModel objects in the cases where a table's rows are sub-tables.
 
Nathan Shields
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think I'm just going to use an h:panelGrid and css/beautify it a bit. I hate to be a quitter, but sometimes you need to eat the sunken time and switch your approach :)
One last question, however: The tables will show correctly the second time the button is clicked. Is there a way to simulate the second button click, without forcing the user to do so? I tried adding an action listener:


Where both loadBoard1 and loadBoardListen1 call loadBoard(1), but it didn't change anything. Any suggestions there?

Once again, thanks so much for all your help, and it's nice to know I'm not just simply being dumb :D
 
Tim Holloway
Bartender
Posts: 18709
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, actionListeners are not totally useless, but about 95% of the time, they get used when they shouldn't be. Generally everything you need can be handled by the action method itself.

As far as updating goes, I have found that AJAX updates can be tricky and sometimes you have to rerender at a higher level than you would expect. In your case, that would probably be re-rendering the object that contains the table, instead of the table itself.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!