voyent
ICEfaces equivalent to Oracle ADF Faces' tableSelectMany upcoming?  XML
Forum Index -> Components
Author Message
zzzz8

Joined: 07/Dec/2005 00:00:00
Messages: 270
Offline


Will ICEfaces offer something similar to Oracle ADF Faces' tableSelectMany component any time soon? This would be a table that has multi-select capabilities (e.g. allow a user to insert or delete rows based on the rows selected).

http://www.oracle.com/technology/products/jdev/htdocs/partners/addins/exchange/jsf/doc/tagdoc/core/tableSelectMany.html

I'm in need of this type of component (and perhaps others) - obviously, it would be nice if ICEfaces could make an equivalent component available (compatible with asynchronous page updates, too).

Normally, this wouldn't be very difficult, as I could add a property into the model like "markedForDeletion" that indicates that this object should be deleted (for a multi-select deletion). Unfortunately, this isn't very elegant nor is this easy in my case because I'm using JAXB to unmarshal data into an object (and which I will later marshal back into XML). I don't think I should or could modify this generated object directly.

If anyone knows of a nice, elegant solution to this problem, please let me know. Obviously, the selected row should be kept selected in face of asynchronous page updates. It would be really, really nice (I guess I'm dreaming here) if I could mark certain properties as the "primary key" for an object. For example, let's say I have a row with the following information:

Name Address Online
---- ------- ------
John CA Yes

Then, this user John goes offline so the data becomes:

Name Address Online
---- ------- ------
John CA No

It would be nice if I could mark name and address as the "primary keys" - so even though I selected this row for deletion or insertion (or whatever), an asynchronous update (or synchronous) to the Online from yes to no will not cause this row to be unselected...

Anyway, if multiselects are not currently possible (or easily done) for data tables, what is the best way to add an option for a user to delete (or insert or whatever) a row from a table - without resorting to changing the model? For example, I would have a delete button for every row. I know that you can assign an action listener for the delete buttons. You can then have the bean listen for the action, retrieve the source component for this event, and then retrieve the parent components for this button... But how does one know which row should be deleted so that you know which row to delete in the data model? I couldn't find anything in the UICommand API nor the UIData API that would allow me to determine this (I'm probably missing something though). Will this cause any problems with ICEfaces?

Thanks!
zzzz8

Joined: 07/Dec/2005 00:00:00
Messages: 270
Offline


I guess I should have investigated this a little more. I guess the getRowIndex() of the wrappted DataModel would let you retrieve the currently selected row (where the button was pressed). So if I just have a bunch of insert or delete buttons for each table row, then it's not too difficult to implement.

I'm not sure to elegantly accomplish this for multiselects. Would I have to create a backing bean that would iterate over all the UISelectBooleans of a table? I would then check and see if each component has been selected, but that seems fairly ugly to do. And I'm also looking into nested data tables, so things get even uglier. If anyone has a good idea as to how to easily do this without creating a messy backing bean, please let me know.

I'm still concerned if there will be any problems with asynchronous updates while using a technique such as the one above (getRowIndex). I assume there will be issues if the data model changes in the time between the pressing of a button (that invokes an action or action listener) and the time the server is able to extract the row index. If the data model changes during that time, the row you may want to delete (insert, etc.) may not be the one you want to change. Will there be any issues or am I misunderstanding something? Or maybe I'm not thinking clearly... it's Friday.
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


Rather than iterate over the UISelectBooleans in the table, it might make sense to bind each UISelectBoolean to a "row" bean. Then, when a single delete button is pressed, the application can iterate over the row beans and take action depending on their selected state.

Problems with asynchronous update could occur -- if the user is modifying the data while the application is modifying the data, there could easily be conflict. Perhaps each row bean could contain a unique key so that an item is not deleted simply because of its row index.
[Email]
zzzz8

Joined: 07/Dec/2005 00:00:00
Messages: 270
Offline


Hi Ted,

I hate to ask this (and this pretty much shows much JSF ignorance), but how would one bind each UISelectBoolean to a row bean? I guess I'm not sure how to deal with binding components that occur several times - usually, when I do a bind, it's usually a one to one correspondence - e.g. an HTML table binds to a UI data component:

public UIData getTable() {
return table;
}

public void setTable(UIData table) {
this.table = table;
}
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


If there are multiple users modifying the data, it's really up to your application to decide how to handle that. You probably don't want to lock the table just for reading. Ideally, when data is modified in the database, a notification should be sent to the application and any users viewing a modified item should have their view updated via an application-initiated render. However, they shouldn't lose what they're working on, either.

The database might not support this, or it might cause too much activity to perform well, so the next best thing would be to let users work on their data as they please but give them options when a conflict occurs. They could chose to apply their data on top of the conflicting data or discard their data, and you would probably want to show which other user entered the conflicting data. Note that this approach also works for offline operation.

So, solving the problem in general is complex and application-dependent, but there's probably a reasonable policy you can take for your particular case depending on how small the records are and what the conflicts mean in the real world (maybe you can just lock individual records). The conflicts in the table occur because two different users are trying to do two different things. In some ways it's more of a social problem than a software problem.

Can you give a concrete example of the data and a conflict?
[Email]
zzzz8

Joined: 07/Dec/2005 00:00:00
Messages: 270
Offline


I'm not actually connecting to a database for this data, so I cannot immediately commit back the data.

Nevertheless, what happens if there is a change to the associated database table between the time you read the data by calling getRows and the time you commit it? I can imagine multiple users modifying the table. Wouldn't you see this problem unless you locked the entire table? I would think one would have to go through the entire process (I think I may have added an unneeded step in the process) I listed in my previous email in order to retrieve the latest data (from the database or elsewhere), yet preserve any rows that are selected.

Anyway, I assume you're suggesting this (I think I forgot to add the primary keys in the last email - in this, I assume a one field primary key), where one would populate the row bean's primkey field with the appropriate field from the BusLogic object:

public class RowBean {
private boolean flag;
private BusLogic busLogic;
private String primKey;

public boolean getFlag() {}
public void setFlag(boolean flag) {}
public BusLogic getBusLogic() { }
public void setBusLogic(BusLogic busLogic) { }
public String getPrimKey() { }
public void setPrimKey(String primKey) { }
}

Again, thanks for all the help and info.
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


Can you generate the array of rows from the database each time getRows() is called? Then each RowBean just needs to know its primary key (since each RowBean probably represents a record) to know where to commit back
to the database.
[Email]
zzzz8

Joined: 07/Dec/2005 00:00:00
Messages: 270
Offline


Hi Ted,

Thanks for the reply.

I think I understand your reply but I can't seem to figure out how one would associate each instance of the RowBean with a unique piece of real data in the back end. I assume you mean something like this:

<pre>
// Class that contains the business logic
public class BusLogic {
private String field1;
private String field2;

// Getters and setters, etc.
}

public class RowBean {
private boolean flag;

private BusLogic busLogic;

public boolean getFlag() {
}

public void setFlag(boolean flag) {
}

public BusLogic getBusLogic() {
}

public void setBusLogic(BusLogic busLogic) {
}
}

public class TableBean {
public RowBean[] getRows() {
return rowBeans;
}
}

</pre>

<h:dataTable var="row" value="#table.rows}">
<h:column >
<h:selectBooleanCheckbox value="#{row.flag}"/>
<h:outputText value="#{row.busLogic.field1}" />
<h:outputText value="#{row.busLogic.field2}" />
</h:column>
</h:dataTable>

I guess I'm still confused how you would create and maintain such an array of RowBeans. Tell me if this is correct (and I guess I would need additional code in the TableBean to handle this stuff):

To create the initial array of RowBeans, you would need to read in the business data (let's say it's a list or an array). So you would iterate through the business data (let's say an array of BusLogic). Then for your choice of primary keys for the BusLogic (let's say you select field1), you would build the array of row beans. OK, the initialization seems fairly easy.

However, the question is how you would maintain such a thing, especially in the face of asynchronous updates. I think there would be a few scenarios. Let's say the business data changes - a few of the original rows are gone and some new data (rows) have been added. Before every invocation of the render pass, I would then have to iterate through the business data. Each "row" of the business data would be compared with an existing row bean. If there is an existing row bean instance with the same primary key, I update the row bean instance with any changed data (other than the primary key). If there is new business data that is not found in the RowBean array, I would need to add a new instance to the RowBean array. And last of all, if business data has been deleted, it would seem that I would actually have to go through the RowBean array and compare it with the business data to see if it has been deleted. All this needs to be done before a render pass.

I guess I have to shudder at this for now - it seems a bit messy. It again begs the question, will ICEfaces be making a component to handle this? :) I'm too lazy to do this! LOL.
ted.goddard

Joined: 26/Oct/2004 00:00:00
Messages: 874
Offline


All questions related to ICEfaces and JSF are welcome on the forum; especially on an advanced JSF technique such as this.

The idea is to use an actual bean to define the contents of your row:

<pre>
public class RowBean {
public boolean getFlag() {
}
public void setFlag(boolean flag) {
}
}

public class TableBean {
public RowBean[] getRows() {
return rowBeans;
}
}
</pre>

<h:dataTable var="row" value="#{table.rows}">
  <h:column >
    <h:selectBooleanCheckbox value="#{row.flag}"/>
  </h:column >
</h:dataTable >

Then, each particular instance of the RowBean just needs to take care that it is associated with a unique piece of real data in the back end.

Does this seem like what you're looking for?
[Email]
zzzz8

Joined: 07/Dec/2005 00:00:00
Messages: 270
Offline


I'm not sure what you mean by "give a concrete example of the data and a conflict." - but I probably can't give one right now. :) Nevertheless, I've probably taken this topic too far, but I certainly get your point now and I have an idea as to how I could possibly approach creating a multiselect table with ICEfaces. Again, thanks for all your help!
 
Forum Index -> Components
Go to:   
Powered by JForum 2.1.7ice © JForum Team