Friday, October 2, 2009

Custom Declarative Components in ADF Faces Rich Client

There is one not well advertised, but great feature in Oracle ADF framework - Custom Declarative Components development for ADF Faces Rich Client. Its really powerful thing, because it allows to build your own components based on groups of standard ADF Faces Rich Client components. There is an article on OTN written by Frank Nimphius, where he describes how you can build, deploy and use this type of components - How-to bind Custom Declarative ADF Faces Components to ADF. In my post, I will give you an example of practical usage, and will describe how Custom Declarative Components can be applied.

Download sample application - AdvancedLOVComponent.zip. This archive contains two JDeveloper 11g R1 applications. One implements Custom Declarative Component, and second is using this component. Developed component represents LOV and description field as one element. Its very common requirement coming from Oracle Forms, to give LOV component and provide description text as well. In Oracle ADF, its usually developed with two ADF Faces Rich Client components - af:inputListOfValues and af:outputText. But, why not to put those two into one and create our own LOV tag. This component will join af:inpitListOfValues and af:outputText:

There is PartialTrigger dependency declared on af:outputText from af:inputListOfValues. And af:inputListOfValues is set as AutoSubmit component. This will allow to change LOV description text value, when LOV value itself is changed.

Component is developed in generic JDeveloper 11g R1 project and supports declarative component metadata:

Main trick with those components is that we can set attribute values on runtime dynamically, from declared attributes. In my sample I'm providing five attributes, among them LOV value and model values, labels and LOV description text value:

This set of input attributes can be extended anytime, without affecting already created usages on your pages.

If we will look into component source code, we will see standard LOV and Output Text tags. Only one specific, those tags get attribute values from declared input attributes instead of bindings:

You need to deploy developed component to ADF Library in order to use it in your project:

Now we will switch to application, where we will use development component on JSPX page. Before using custom component, you need to declare custom tag library:

When custom tag library will be declared, components will be present in Component Palette window:

Drag and drop custom component to JSPX and you will see it in Structure window:

Let's see in source code - one custom tag andrejusb:ListOfValuesAdvanced implements two standard components - af:inputListOfValues and af:outputText. That's great, because it can save development time for LOV's at least twice. And it's not only about time, but about code quality and reusability:

Attribute values for custom tag are set in standard way - from bindings.

On runtime, custom tag is rendered as DepartmentId LOV and description text for specific LOV value (Control And Credit in this case):

LOV from custom tag works same as standard LOV. Let's open LOV popup and change current value:

When new value is selected in LOV, description text is updated as expected. And both elements are present on JSPX as single element:

26 comments:

  1. Hi Andrejus,

    Thanks for sharing your simple and powerful component.

    If you replace the "af:outputText" with "af:inputText"-> disabled="true" then you have control over the columns allocated for the "description" part of the LOV.
    So if you specify an attribute for the "columns" of the disabled af:inputText then you get a visual indication for the space allocated for it similar to the one you get from Forms.

    Again, thank you for sharing your thoughts with us.

    PS: The original idea for the custom CRUD security perceived from:
    AdvancedViewObjectExamples.zip --> DeclarativeBlockOperations --> CustomViewRowImpl class
    http://www.oracle.com/technology/documentation/jdev/b25947_01/index.html

    Best Regards,
    Elias.

    ReplyDelete
  2. Hi Andrejus,

    This is really a great component, the only addition would be that, to make sure that the labels align up correctly in a panel form, It seems we would have to wrap it in an af:panelLabelAndMessage component. and set the "simple" property of the lov to true.

    This will ensure that the component and it's labels properly align with all others on the form. Though it means a bit more work for those using the component, it is definitely still worth it.

    Thanks

    ReplyDelete
  3. Hi Guys,

    Thanks for your comments regarding layout. In this post, I intentionally have tried to avoid any recommendations regarding layout. Because, it depends from project to project and usually is based on specific requirements.

    Once again - thanks for comments, its helpful.

    Andrejus

    ReplyDelete
  4. Hi!
    Tnx for simple and clear explanation and example. Now I'm trying to create some declarative components for our project and I'm stuck with a problem. If I need only to expose some simple properties like label or value then everything works fine. But here is such a situation: my component represents a panel with some inputText's, every one of which has its own binding. So far I was unable to create properties for these bindings. Say, I have an input for some address and I add attribute
    <attribute>
      <attribute-name>
        address_binding
      </attribute-name>
      <attribute-class>
        java.lang.Object
      </attribute-class>
    </attribute>
    And I set it like this:
    <csc:MyComponent id="p1"
    ...   address_binding="#{pageFlowScope.parentInsertViewBean.c_IndividualAddress}"
    />
    using the same binding I use for separate inputs. And by doing so I get the runtime error:
    javax.el.PropertyNotFoundException: The class 'oracle.adf.view.rich.component.fragment.UIXInclude$AttrMap' does not have the property 'address_binding'.
    at javax.el.BeanELResolver.getBeanProperty(BeanELResolver.java:547)
    ...
    Can you tell me, what can be possibly wrong with it?

    ReplyDelete
  5. Hi,

    I have a little problem with Your component. When I try to change the department_id to new value and then save it to database, nothing is happening. In database I have old value. Is there any way to fix this problem?

    Best Regards,
    Peter

    ReplyDelete
  6. I'm not sure, I checked - it works in my application. Are you testing my app?

    Andrejus

    ReplyDelete
  7. Yes. I was testing Your application. I've checked it in version of Jdev. First 11.1.1.2 and it works. Second 11.1.1.3 and doesn't work. Maybe something was changed in the new version?

    Peter

    ReplyDelete
  8. Hi Peter,

    Yes, I tested in PS2 - it doesnt work as expected. I will check this and will post update.

    Regards,
    Andrejus

    ReplyDelete
  9. Hi Andrejus

    One more little thing about this component. Based on this I tried building a component of my own, but I can't get the validator to work for fields that are mandatory, for example. As such a user can scroll through records without an error being raised. Is there a way that the validator could be passed into the component?

    Thanks

    Femi

    ReplyDelete
  10. You can add validator into reusable component.

    Andrejus

    ReplyDelete
  11. Peter,

    Please find updated sample to JDeveloper 11g PS2: http://andrejusb.blogspot.com/2010/05/jdeveloper-11g-ps2-update-custom.html

    Regards,
    Andrejus

    ReplyDelete
  12. Hi Andrejus,
    When I click on link given in your blog to Frank Nimphius' article in OTN , it redirects to http://www.oracle.com/technetwork/developer-tools/jdev/overview/index.html

    Do you know why is it happening?
    Can we give us the link to Frank Nimphius' article in OTN ?

    ReplyDelete
  13. Hi Andrejus,

    Awesome post.

    I am trying to create simple custom component for two input fields - PhoneNumber and Mobile Number.
    Two achieve that, I simply included two input text in my custom components. Both fields should display the numbers in different formats.
    Phone Number - xxx-xxx-xxxx
    Mobile Number - +xx-xxxxxxxxxx

    Value displayed should be in required format but it needs to binded to phoneNumber and MobileNumber at backend which accepts complete number.
    How to incorporate custom converter and validator for the custom component created ?

    Thanks,
    Rajdeep

    ReplyDelete
  14. Hi Andrejus,
    first of all thank you for your post! I need to use my custom declarative component in a bean because I'm going to create it on the page at runtime. The code that works for common items doesn't work for my customized declarative component. If I put it on the page with drag and drop everything works perfectly but if I create it in a bean nothing happens (I get no errors). I'm using JDeveloper 11.1.1.4.0, can you tell me if it is possible to do that?
    Thanks!

    ReplyDelete
  15. Link to Frank's article seems to be broken. I found it at http://www.oracle.com/technetwork/developer-tools/jdev/declarative-component-adf-084567.html

    ReplyDelete
  16. can you do me favour.

    can you give some suggestion on this thread.
    Thread: af:inputListOfValues in adf
    https://forums.oracle.com/forums/thread.jspa?threadID=2336242&tstart=0

    ReplyDelete
  17. Hi ,

    I would like to implement an ADF custom component. I have a link where the steps are given. I followed it. But some code are missing and since I am a newbie to ADF , I have no idea on how to code this component.
    Kindly let me know what the doc has missed and how we can code this component.
    http://docs.oracle.com/cd/E21764_01/web.1111/b31973/ad_custom.htm

    ReplyDelete
  18. I created a simple custom component to wrap a text field in a hidden trim() tag so that numbers are treated as strings when exported to excel and don't display in exponential notation or trim leading zero's. It works fine except if I use this component in more than one column of a table I get this message logged for every row being exported for every column containing the component. So If I export 1000 rows each having 4 columns containing my custom component it logs 4000 errors. But the export works. Any idea's?


    During the processing of the include component, the context change found did not match the current component.

    ReplyDelete
  19. Hi Andrejus,

    I have an basic doubt. Can I create an another jspx (Ex.DecInputText.jspx) file in the application DeclarativeComponents, LOVAdvanced project. Add it an InputText and deploy as a InputText.jar.

    Can I create a multiple different reusable component in a single project.

    Please provide the rules to create Declarative component.

    Thanks and Regards
    Mohanraj

    ReplyDelete
  20. Hi Andrejus,

    I have created a custom component for my project. I have added component on two places on my jspx page but the component is getting rendered only once on my page. I could see only one component how many ever I add on my page.
    have you observed any such? Can you help me here.

    Thanks in advance

    ReplyDelete
  21. Make sure, you are using Backing Bean Scope for managed beans in Declarative component.

    Regards,
    Andrejus

    ReplyDelete
  22. Hi Andrejus,

    Where it's possible to download the advancedLOVcomponent.zip example?

    Thanks very much

    Itshak

    ReplyDelete
  23. Do you rename the zip file name? I search the 24 pages and does not found the advancedLOVcomponent.zip file

    Thanks again

    ReplyDelete
  24. You should search by date, it is there - https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jdevsamples/AdvancedLOVComponent.zip

    ReplyDelete