Tuesday, November 27, 2007

JDeveloper 11g - Create, Edit and Delete operations in ADF Faces af:table component

In this post, I have decided to implement JDeveloper 11g Technical Preview 2 sample application, based on one of my most popular blog post - Create, Edit and Delete operations in ADF Faces af:table component. I already received several requests to provide sample application for similar functionality in JDeveloper 11g, so here it comes.

Developed sample application EditableTable11.zip, provides read-only table with those actions - Delete, Create, Edit, Save, Cancel. Row selected for editing is shown in editable mode and can be updated. Application is based on HR schema that comes with Oracle XE database. Application logic is based on Jobs entity from HR schema.

This sample is developed using the same principle as described in my previous post. I will describe what are the differences in implementation:

1. In JDeveloper 11g CreateInsert operation is not hidden anymore, you can use it directly from Data Control. This operation is used to create new row in table:


2. In From field of af:setActionListener, defined for Edit button, is used access to row - #{bindings.JobsView1Iterator.currentRow}, instead of access to individual column - {row.JobId}.

3. isEnableEditing() method in ValueHolder.java is changed, new code:


What's the difference here? First thing - since ValueBinding is deprecated, I'm using ValueExpression to access column value in a table. And second - I'm using oracle.jbo.server.ViewRowImpl to hold selected row.

How it works? JDeveloper 11g comes with ADF Faces Rich Client, it gives new level of usability in Web applications - you will notice this immediately. Create functionality is invoked by pressing Create button:


When data is entered, Save button allows to store information into database:


There is no more ugly radio button components for row selection, you can use just your mouse to select any row for editing:


And finally, several words about some of new features available in af:table component that comes with JDeveloper 11g ADF Faces Rich Client. First feature - standard functionality allows to rearrange columns in a table on runtime:

Filter can be used, to execute search directly in the table:


And, when let's say wrong input is provided, nice error message is shown at the same time when new value is typed:


I'm sure, you will like af:table component that comes with JDeveloper 11g ADF Faces Rich Client ;-)

36 comments:

  1. This is extremely impressive. Thanks for sharing the information with us, this will drop web-app dev time enormously.

    Oracle continues to impress.

    ReplyDelete
  2. It's very interesting. When I click create the program successfully creates a new row, as long as the first row in the table is selected. However, if I select any row other than the first row before clicking the "Create" button, the values I enter are used to update the first row rather than to create a new row. I am using TP3 for my test. Do you know why this is happening?

    Larry

    ReplyDelete
  3. Hi Larry,

    I tested it as you described and I'm getting the same behavior. It seems a bug in TP3.

    I have developed workaround - create Method Action for Create button and replace generated code with:

    public String createButton_action() {
    BindingContainer bindings = getBindings();

    DCIteratorBinding dcib = (DCIteratorBinding) bindings.get("JobsView1Iterator");
    RowSetIterator iter = dcib.getRowSetIterator();
    Row newRow = iter.createRow();
    iter.insertRowAtRangeIndex(0, newRow);

    return null;
    }

    This code will put new row always as first row in table, even if selected row is not first.

    If you want, drop me an email, I will send you updated application.

    Regards,
    Andrejus

    ReplyDelete
  4. Yes, that works. Thank you very much for your help. At least I now have code that works.

    It's very annoying that I can't force the table component to insert anywhere except at the top.

    I AM able to change the table's "rowIndex" property to point to the selected row using code like this:

    RowKeySet rks = this.getTheTable().getSelectedRowKeys();
    System.out.println("Number of selected rows is >" + rks.getSize() + "<");
    Iterator selection = rks.iterator();
    while (selection.hasNext()) {
    Object rowKey = selection.next();
    this.getTheTable().setRowKey(rowKey);
    }
    System.out.println("Now the current row index is >" + this.getTheTable().getRowIndex() + "<");

    Note that I have the table configured to only allow single-row selections, so there is always only 1 row in the RowKeySet.

    However if I try to insert the new row at the selection position like this:

    rowNumForInsert = this.getTheApplicationTable().getRowIndex();
    iter.insertRowAtRangeIndex(rowNumForInsert,newRow);

    it makes no difference and the table still applies the data to whatever row is at the top.

    I agree with you that it is most likely a bug in the RichTable component in TP3.

    Larry

    ReplyDelete
  5. Hi Andrejus,
    What if i add rows to the underlying View Objects rather than the af:table itself ?

    I want to add rows after the selected row in the af:table. Could you please tell me if its possible in TP4 ? Please share the code if so..

    Thanks in Advance
    Raj

    ReplyDelete
  6. Hi,

    You can check my older post, same principle applies to TP4 also: Create multiple rows in Oracle ADF.

    Regards,
    Andrejus

    ReplyDelete
  7. Hi Andrejus,

    I had expected the multiple selection of rows to be multiple delete enabled by default but that does not seem to be working. I enabled 'multiple' option for row selection but am not able to delete multiple rows.

    Can you throw some light on how to delete multiple rows from a adf Rich Table component?

    Thanks and regards,

    Arun

    ReplyDelete
  8. Arun,

    It deletes only first from selected rows?

    Andrejus

    ReplyDelete
  9. Hi Andrejus,
    I have PL/SQL package converted to java with jdeveloper 11g. On that package i have a createModify function, wich is the function that i must use to create or modify a row in the table.

    I´ve tried to make a new data control with the .java file, and from that data control take createModify function and throw as a commandButton in the page. But ¿how can i say to the function to take the selected row´s atributes as parametres of the function?

    Is that the correct way to do this?

    Or is it best to create a managed bean?

    Rowan

    ReplyDelete
  10. Rowan,

    I think, in your case it will be better to use Managed Bean.

    Regards,
    Andrejus

    ReplyDelete
  11. OK,
    i will use managed beans.
    So, i use a command button binding to the function of the managed bean that i need. But that function is to create a new row, so firts i need to insert a blank row in the table.
    Where must i put de code of the blank row.
    ¿In my new create funcition? or ¿can i use the createinsert function and bind it to my newcreate function?

    Thanks,

    Rowan

    ReplyDelete
  12. Hi Andrejus,

    I actually got a method that calls a for loop over the RowKeySet to delete the rows that are selected with ctrl+mouse click. The rows get deleted from the UI and the table refreshes to reflect the remaining rows. But I am facing an issue with commit...

    The error is that that "JBO 25019: Entity Row of Key oracle.jbo.key[*KeyValueHere*] not found in DetailEO.

    The method that I added to the manage bean to perform the delete is:

    public void onDeleteLevel1(ActionEvent actionEvent) {

    FacesContext fctx = FacesContext.getCurrentInstance();
    Application application;
    application = fctx.getApplication();

    ELContext elctx = fctx.getELContext();
    ExpressionFactory exprfactory = application.getExpressionFactory();

    ValueExpression valueExpression = exprfactory.createValueExpression
    (elctx,"#{bindings}",Object.class);
    DCBindingContainer dcbinding =
    (DCBindingContainer) valueExpression.getValue(elctx);

    FacesCtrlHierBinding treeRootNode =
    (FacesCtrlHierBinding) dcbinding.get("RatingLevel");

    RowKeySet rowKeySet = (RowKeySet)getRatingsTable1().getSelectedRowKeys();
    for (Object facesTreeRowKey : rowKeySet) {
    getRatingsTable1().setRowKey(facesTreeRowKey);
    JUCtrlHierNodeBinding rowData =
    (JUCtrlHierNodeBinding) getRatingsTable1().getRowData();
    ((JUCtrlHierNodeBinding)treeRootNode.getCollectionModel().
    getRowData()).getRow().remove();
    }
    }

    I read that the error is caused because the remove() operation will cause the entity row to be removed from cache.

    Can you please suggest how do I update the cache to retain the lock and then perform the commit.

    Thanks,

    Arun

    ReplyDelete
  13. following this example(yours), i created a new one. after execution on browser, when i performs the second action (for any action like sorting: first action is desc then the second action asc) it returns the error like this:
    Messages for this page are listed below.
    Empno Error
    java.lang.NullPointerException
    Empname Error
    java.lang.NullPointerException
    Empdob Error
    java.lang.NullPointerException
    Salary Error
    java.lang.NullPointerException

    plz.. help me

    ReplyDelete
  14. I get the same error. I just tried to implement my own version and on the two mandatory fields in my table, I get a nullPointerException in the ADF popup error box. Any thoughts ?

    ReplyDelete
  15. Hi,

    I know how to solve your problem. Its a bug in TP4 JSF library.

    Temporary and quick solution is to remove f:validator tags for all columns in the table. It will solve this problem.

    Regards,
    Andrejus

    ReplyDelete
  16. Hi Andrejus,

    I am having difficulties making this work from scratch in the new JDEV 11G release.

    When I add a row, enter nothing and hit cancel the rollback does not clear away the row.

    Can you test this example out in 11g and see if it works for you?

    Mark

    ReplyDelete
  17. I will test it, will post update.

    Regards,
    Andrejus

    ReplyDelete
  18. Thanks for your wonderful blog. I'm also new to Jdev11g & so may I ask how I could achieve this functionality? What I would like to do is to show a popup dialog and prompt users for input instead of inline row editing. So, how do I detect whether a row is being selected to disable/enable the Edit button accordingly? Using your example, I tried this EL expression but it does not seem to work. Am I missing sth?

    disabled='#{bindings.JobsView1Iterator.currentRow== null}'

    Thanks in advance,
    Phil

    ReplyDelete
  19. Hi Andrejus,

    I found that my specific problem with JDEV 11G and this create edit delete table is something to do with the cancel button and Rollback.

    When I add a new row and decide I want to cancel, it won't get rid of the new row.

    Any thoughts ?

    Mark

    ReplyDelete
  20. Hi Andrejus,

    May i know how can i remove the selected row in ADF table using the code. I need to remove the selected row when another action occurs. So i have the actionListener and the blinded RichTable reference in my backing bean.

    Thiva

    ReplyDelete
  21. Just found that we can remove the selected row by using the tichTable::getSelectedRowKeys().clear();

    Thiva

    ReplyDelete
  22. Hi, wonderfull post I have the problem java.lang.NullPointerException with the create method, and I already remove the af:validator but still the same, any clue?

    ReplyDelete
  23. Hi,

    I am following the same example for one of my requirement but i found that On create operation if any DB validation failed i found that table row has became read-only. But same thing is not happening on the Edit.

    Please guide me how to resolve this issue.

    ReplyDelete
  24. To- Andrejus Baranovskis

    How to insert new record in database using ADF form in jdeveloper 11g? How do I use createInsert operation to insert new record?

    ReplyDelete
  25. Hi, Andrejus Baranovskis,

    Your solution is really nice. But when deploy it in JDev 11.1.1.4, after click "Edit" button, then click "Cancel" button, all the rows become editable. Did you ever see this phenomenon?

    Really appreciate if you can have a look!

    Best Regards,

    Alfred

    ReplyDelete
  26. Hi,

    I have updated sample application, it works now on 11g PS3. Please download again ;)

    Andrejus

    ReplyDelete
  27. Hi, Andrejus Baranovskis,

    You are so efficient. Cool!

    Best Regards,

    Alfred

    ReplyDelete
  28. Hi Andrejus
    I am a newbie and have read most of your works/posts in the internet. Do you have anyother consolidated source where I can get all the information you post?

    I have some questions regarding this post btw:
    1. when you set disabled property in the cancel button for eg., you also set which other button has to be disabled at the time this cancel button is enabled. For instance we have !valueHolder.editAction for the disabled property for cancel btn. The questio I have is how this is set or unset using the bean as I see no direct method being called and only the property. how the set/unset take place as you dont explicitly set a listener. The last question is I dont understand the af:setactionlister that well as I dont find any doco on this on the net. please find some time to help
    Thank you
    Les

    ReplyDelete
  29. Hi Andejus,
    After selecting the row in my adf table I am clicking delete and it deletes the row but when i press save and tries to commit the transaction, it throws
    "Attempt to access dead entity in xyzEO, key=oracle.jbo.Key[10 ]

    Any pointers ??

    Thanks
    Sumit Yadav

    ReplyDelete
  30. Hi ,
    I got the issue, actually after deleting the row, in my EOImpl of that vo,in the DoDml() method i was trying to set the lastUpdatedBy column value and since the row is already deleted it was not able to find a reference which was throwing the error .
    Foe resolution, i am now checking the state of the row by
    if (this.getEntityState() != STATUS_DELETED)
    and executing accordingly .

    Thanks
    Sumit

    ReplyDelete
  31. can

    you help me.

    http://forums.oracle.com/forums/thread.jspa?threadID=2267085&tstart=0

    ReplyDelete
  32. Hello,
    How could I add the row in a Form instead of a table? Same logic? for 11g.

    Thanks

    ReplyDelete
  33. Hi,

    Yes - may be this post will help you: http://andrejusb.blogspot.com/2008/09/jdeveloper-11g-crud-in-adf-form.html

    Andrejus

    ReplyDelete
  34. Hello I am new to ADF, I would like to know if you have an example of an ADF table with basic CRUD functionality, but you can choose which rows will save, by selecting a row for selectBooleanCheckbox. It is possible?
    Please I need help.
    Thank you very much.

    ReplyDelete
  35. Hi Andrejus,

    I am using 11g PS3. IT is working verygood.

    I have a requirement to implement sequence for job id, but when i implement a sequence and when i create a new row it is in read only mode.

    Can you please help me with this scenario.

    Thanks
    varma

    ReplyDelete