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:

15 comments:

  1. 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) ???

    ReplyDelete
  2. 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

    ReplyDelete
  3. Afroz.

    Did you find a solution for your behavior?

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

    Regards,
    Andrejus

    ReplyDelete
  5. 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;
    }

    ReplyDelete
  6. 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);
    }
    }
    }
    }

    }

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

    Andrejus

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

    ReplyDelete
  9. Hi Andrejus,

    Thanks for a nice post. I had a similar kind of requirement. there is a table in a page. a user can select multiple rows. On selecting the rows I need to change the background color of the selected rows. How can we achieve this.

    Thanks in advance...

    ReplyDelete
  10. hi, thinks for this post
    please can you refresh the link because i cant download the source!
    thinks

    ReplyDelete
  11. You can find it here - https://code.google.com/archive/p/jdevsamples/downloads

    Andrejus

    ReplyDelete
  12. Hi Andrejus,

    I am facing problem with 'FacesCtrlHierNodeBinding' class.
    it show illegal internal package while importing package
    'import oracle.adfinternal.view.faces.model.binding.FacesCtrlHierNodeBinding'

    Rahul

    ReplyDelete
  13. You should switch to similar public class. Search on Google - there are answers on Forum with proper public class name.

    Andrejus

    ReplyDelete
  14. Not able to download ur sample application. please share AMIMPL method "getRowStatusColor"

    ReplyDelete
  15. You can download it from Google Archive: http://andrejusb.blogspot.lt/2017/08/my-blog-samples-download-repository-for.html

    Andrejus

    ReplyDelete