Sunday, April 18, 2010

Dynamic Iterator Binding to Reuse View Link Relationship for Master-Detail

Its very frequent requirement to implement Master-Detail relationships. Additionally it happens to render detail or master data for the same table, based on user selection. For example, we can have master screen with Locations data and another screen with detail data for Departments. But, if user opens Departments screen directly, it should bring complete list for Departments. So, complexity here - how to implement detail table for Departments data, with option to bring complete list of Departments as well.

This requirement can be solved mainly in three ways:

1. Duplicating Departments fragment - one for master and another for detail data
2. Implementing View Criteria to filter Departments conditionally
3. Implementing dynamic iterator binding and reusing View Link relationship

First option is highly not recommended, because it increasing number of fragments or pages - this means duplicating number of bugs. Second option is good and simple, however you need to declare View Criteria and filter View Object based on parameter. It works well, however we are not using built in ADF support for Master-Detail relationships. Third option - dynamic iterator binding works the best, because there is no need for View Criteria and we are reusing View Link functionality given by ADF.

Download sample application - This sample implements a use case, where Departments data is rendered based on dynamic iterator declared in Page Definition.

As you can see from Data Control, we have two instances for Departments VO - DepartmentsMasterView and DepartmentsDetailView:

Controller layer implements Router activity, to open locations or departments fragments based on external parameter. If departments fragment will be opened directly, it should bring all departments:

In this sample, I'm mainly focusing on departments fragment and its Page Definition. Iterator for departments data:

Is binded to VO instance dynamically, using Expression Language. Based on page flow scope parameter, we set to use Master or Detail VO instance. Iterator binding is set dynamically:

Master and Detail instances for Departments VO:

Page flow scope parameter is set from Locations fragment:

Its value is initialized with Departments detail instance name - DepartmentsDetailView:

We can test it now, lets run our region with departments external parameter value, this will trigger conditional navigation in Router activity and will map master VO instance for departments iterator:

All departments are rendered by departments fragment:

We can navigate to Locations and select one of the locations, for example 1700:

Departments data is filtered now automatically, through View Link relationship implemented between Locations and Departments. This means, iterator for departments was initialized based on DepartmentsDetailView instance:


Tiah said...

Very nice Andrew. It is really helpful in making many of my systems really dynamic.

Thanks again,

Til said...

Thanks a lot Andrew this is great but how can i do this programmatically with Bean
can you put the code to do this in a bean to change the iterator .

thanks a lot

Andrej Baranovskij said...

Just access PageFlowScope and change variably programmatically. It will work from the bean.

Andrejus said...

Hi, Great Article, it is simple and easy to follow. However, I am currently creating an application for the web using JSF. In one of my JSF I have an ADF visualization Bar graph in a Panel Group layout and five buttons in another panel group layout below the graph. I would like to cause the graph to change according to the button I click. The data source for each graph is different. Would appreciate any help you could render. Thanks in advance

Ravi said...

Thanks for your posts,

I am following your posts to learn ADF.
I am trying this post and configured everything as shown in this post.but when i run my page getting below exception.

java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map
at oracle.adf.controller.internal.binding.RegionUtils.getInputParameterValues(
at oracle.adf.controller.internal.binding.TaskFlowRegionModelLocal.getInputParameterValues(
at oracle.adf.controller.internal.binding.TaskFlowRegionModelViewPort.createRegionViewPortContext(

please help me.
Jdev version :