Tuesday, April 6, 2010

Changed Row Highlighting in Oracle ADF Table

User always wants to be informed about changes he did, this means we should keep him informed - moreover with ADF 11g it can be done very easily. Let's say user is changing one row and moving to another, how he will remember what rows were changed and review them once again before submitting to database. Logical answer - by highlighting changed rows. I will describe this use case and will provide sample application.

Download my sample - RowHighlight.zip. You can run this sample on your machine and see that row color will be changed after you will leave edited row and move to the next one.

I'm editing FI_MGR row:


Next I'm changing data for AC_ACCOUNT row, without committing previously done changes for FI_MGR:


You can see - FI_MGR row is highlighted, this informs user that he did changes in that row and those changes will be submitted to database when he will press Save button.

I navigate to the next record - AC_ACCOUNT row becomes highlighted:


After pressing Save button, all user changes are submitted to database and row highlighting is removed:


Now I will tell you, how you can implement described use case. Check my sample application, you will see there in Page Definition file, that I have defined getRowStatusColor method:


This method is calling custom method available in View Object Implementation class - to check current row status. I will need to iterate through range set of rendered rows, this means I will provide method parameter dynamically:


I'm calling this method from Backing Bean class, where I'm evaluating current row status and returning color setting for InlineStyle property of ADF column component:


This means I will highlight each cell individually.

Method in Backing Bean class is accessing rendered row, passing it to getRowStatusColor method and returning red color in case if rendered row is Modified:

8 comments:

Anonymous said...

hi andrejus

thanks for support , but i am new in adf , my task is to create many details for specific master record ( i want add many items for specific customer) ???

Afroz said...

Hi Andrejus,

I am trying to achieve similar result for my table which is read-only. I have check box column to select the row which is bound to "isSelected" attribute of my View object. Selecting the row using this checkbox should highlight the row. I have code like this:

"af:column sortProperty="poName" sortable="true" headerText="#{pdcviewcontrollerBundle.NAME_0}"
id="c3" inlineStyle='#{(row.isSelected)?"background-color: #E7E7E7":""};' "

My issue is, above solution does not work if I do not set partial trigger on table for the check box. However, doing this refreshes whole table everytime I select/deselect the checkbox. Any idea how to resolve this? My table can have huge data and everytime refresh will be overkill.

Regards,
Afroz

Anonymous said...

Afroz.

Did you find a solution for your behavior?

Andrejus Baranovskis said...

Its a bit different problem, not one described in blog post. I think, you will not avoid using PPR.

Regards,
Andrejus

dkleppinger said...

You can change the hightlighted and selected colors by editing the Skin file for your app. Something like this

af|table::data-row:highlighted af|column::data-cell,
af|table::data-row:highlighted af|column::banded-data-cell {
background-color: #DCF0AB;
}

af|table::data-row:selected:focused af|column::data-cell,
af|table::data-row:selected:focused af|column::banded-data-cell,
af|table::data-row:selected:inactive af|column::data-cell,
af|table::data-row:selected:inactive af|column::banded-data-cell,
af|table::data-row:selected af|column::data-cell,
af|table::data-row:selected af|column::banded-data-cell{
background-color: #B2CA7E;
}

Don Kleppinger said...

We were able to accomplish highlighting visited rows using javascript to avoid PPR. I don't guarantee the following code to work because I stripped out much of it that was unrelated to the highlighting but his should be a good starting point. Note that visitedStyleClass is defined in the skin file and ADF will compress this so you need to get the compressed name for it from the backing bean by indexing the styleClassMap
styleClassMap = SkinFactory.getFactory().getSkin(FacesContext.getCurrentInstance(),"YourSkinId").getStyleClassMap(RichAdfRenderingContext.getCurrentInstance());

/**
* Called by double click client listener on table
*/
function handleDoubleClickEvent(evt) {

evt.cancel();
if (evt.getType()=='dblClick' &&
(evt._target.className == "af_table_data-body" ||
evt._target.className == "af_table")) {
// If the event came from the table body (white space), then we don't
// want to continue.
return;
}
*/
table = evt.getSource();

if (table == null) {
return;
}

var rowKeySet = table.getSelectedRowKeys();

// We are only interested in the last row if multiple
// rows are selected.
var lastRowKey = null;

for (rowKey in rowKeySet) {
lastRowKey = rowKey
}

if (lastRowKey == null && navAction == null) {
// Restore cursor to default
document.body.style.cursor = "default";
return;
}

var peer = table.getPeer();
if (peer == null) {
// Restore cursor to default
document.body.style.cursor = "default";
return;
}

// Code to highlight visited row without refreshing data from server
if (typeof visitedStyleClass != 'undefined' && visitedStyleClass != null && lastRowKey != null)
{
var rowInfo = peer.FindRowByKey(lastRowKey);
if (rowInfo != null) {
var row = rowInfo.tr;
if (row) {
var columns = row.cells;
for (var colIndex=0;colIndex<columns.length;colIndex++) {
var col = columns[colIndex];
col.setAttribute("class", col.className + " " + visitedStyleClass);
}
}
}
}

}

Andrejus Baranovskis said...

Thanks for posting this, looks like interesting different approach to solve same requirement.

Andrejus

Aaridraka said...

My View object is not based on entity, it is read only.
Is there any solution for this case?
Thanks in advance. :)