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:

22 comments:

Anonymous said...

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.

Femi said...

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

Andrejus Baranovskis said...

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

brenagwynn said...

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?

mavell said...

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

Andrejus Baranovskis said...

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

Andrejus

mavell said...

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

Andrejus Baranovskis said...

Hi Peter,

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

Regards,
Andrejus

fakintoye said...

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

Andrejus Baranovskis said...

You can add validator into reusable component.

Andrejus

Andrejus Baranovskis said...

Peter,

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

Regards,
Andrejus

Anonymous said...

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 ?

Rakesh said...

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

GstKat said...

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!

Softwarer said...

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

Andrejus Baranovskis said...

Thanks, I will update link.

Andrejus

subra manian said...

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

Steve said...

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

Don Kleppinger said...

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.

Mohanraj said...

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

Anonymous said...

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

Andrejus Baranovskis said...

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

Regards,
Andrejus