Thursday, August 12, 2010

Refresh the parent view when a taskflow displayed in a popup returns

This post discusses an interesting use case on refreshing the parent view when an in-line popup taskflow returns. There are two taskflows, both work with separate transaction contexts(Transaction attribute is set as new-transaction). Second taskflow is invoked from the first one as a dialog. The requirement here is to refresh the 'executables' of calling page(from first taskflow) when the second taskflow returns. This scenario usually arises when the second task flow updates tables used by the first one from a different transaction context.

To learn more on taskflow, please refer Part III Creating ADF Task Flows in Fusion Middleware Fusion Developer's Guide for Oracle ADF.

Cool, now back to the use case. One possible solution for the above scenario is to define a returnListener for secondary window on the command button (which invokes second taskflow as dialog) and add the custom logic to refresh the underlying IteratorBindings used by the parent page. Last step is to manually refresh the parent view by adding it as PartialTarget - RequestContext.getCurrentInstance().addPartialTarget(returnEvent.getComponent().getParent().getParent());
That's it, job is done. I'm copying the relevant code snippet below for your reference.
<af:commandMenuItem text="Create" id="cmi1" action="create"
useWindow="true"
windowEmbedStyle="inlineDocument"
windowModalityType="applicationModal"
returnListener="#{viewScope.RefreshBean.dialogReturnListener}"
windowHeight="250" windowWidth="500"/>
public void dialogReturnListener(ReturnEvent returnEvent) {
  BindingContext bc = BindingContext.getCurrent();
  DCBindingContainer dcb =
    (DCBindingContainer)bc.getCurrentBindingsEntry();
  DCIteratorBinding iter =
    dcb.findIteratorBinding("DepartmentsView1Iterator");
  iter.executeQuery();
  RequestContext.getCurrentInstance().addPartialTarget(returnEvent.getComponent().getParent().getParent());

}

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

How to run this sample?

Run the main.jspx. This page contains 'outer-task-flow-definition' which displays Departments details on a table. Select the 'create' menu item from the toolbar, which opens up 'inner-task-flow-definition' in a popup. Key in the new department details and click on Save. This action closes the popup and then refreshes the parent view to display new record.


Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html

28 comments:

Anonymous said...

Thanks for posting this, however there is one problem with this, you see a blank page for 1-2 seconds and then it loads the view

May be its a ADF bug?

Thanks,
Harry

Anonymous said...

to be specific, second taskflow running as a Dialog with inline-popup it launches and shows blank view till pageDef executed with all data to display.

Harry

Jobinesh said...

Harry,
This seems to be the delay in loading the task flow( server round trip + execution + loading). btw, thanks for pointing out, will try to see whether this can be optimized/fine tuned further.

Anonymous said...

Is there a way to avoid user interaction during the 1-2 sec delay during the page refresh?

Thanks,
Suneetha

Jobinesh said...

Suneetha
You can take a look at this post
http://jobinesh.blogspot.com/2010/10/preventing-user-input-on-fusion-web.html
Please see whether this helps you here

sunil ravinder said...
This comment has been removed by the author.
sunil ravinder said...
This comment has been removed by the author.
sunil ravinder said...

Hi jobinesh,

I have a scenario where the second taskflow is not shown in a popup, but is part of the parent page itself.

If my parent page has a table, how do I refresh the table (as i don't want whole page refresh) when I am doing a save in the second taskflow..

Any ideas ?

Thanks

Jobinesh said...

Sunil,
One possibility is to use Contextual Events. Details can be found here-
http://download.oracle.com/docs/cd/E15523_01/web.1111/b31974/web_adv.htm#CACJBFGI

Daniel said...

Jobinesh,

I am using a inline popup to solve my specific scenario. By default, it already comes with an "x" button that closes the popup. If I add the code you published in some kind of "Close" our "Save" button like you did, if the user decides to close de window by the native X button, it won't refresh the parent page. What would you suggest me do?

Jobinesh said...

Daneil,
One possibility is to embed the taskflow in your own popup and add a popupCanceledListener. Another option may be( not a gr8 solution) hide the close icon using skinning

Daniel said...

Jobinesh,

Thanks for the quick answer! I'm sorry, but i'm still a newbie to ADF. What do you mean when you say "embed the taskflow in my own popup"?
Currently, I have a bounded taskflow for my inline popup (with a close function that calls a taskFlowReturn), and my home page calls this taskflow from a menu option.
I'm gonna do some research on the listener you suggested, thanks!

Jobinesh said...

Daniel,
Please see this link -http://www.oracle.com/technetwork/developer-tools/adf/popupregionpattern-394585.pdf

Anooj said...

Hi Jobinesh,

In my scenario, I am calling the second taskflow as inline popup.

The main issue that I face is to return multiple values from second taskflow to the first taskflow.

Is there a way I can pass and receive multiple values from taskflow.

Jobinesh said...

Anooj
You can return mulitple values out of the box. Another option is wrap them in a an ArrayList and return

Anooj said...
This comment has been removed by the author.
Anooj said...

Hi Jobinesh,

I am able to return multiple parameters using ArrayList.

Can you still update me on how to return multiple values out of the box.

garg said...

If I open 2nd taskflow as a default i.e Run as Dialog=false and Display Type external window then returnListener function never called. Any idea?

Thanks in Advance.

Future-Tech....... inovations of future said...

Helo sir,
this is Ashish

I am working on ERP project using ADF.
I have problem related to ReturnListener that, when User search more than 10 times on the Search form then returnListener method on parant form.

I am not able to trace the error where it occur so please help to overcome from this situation.

thank you.

Dinesh Chakravarthy said...

Hi Jobinesh,

I am trying to open a new browser window as modeless window using commandImageLink/commandButton. I have set following parameters to the above UI components

useWindow="true"
windowHeight="400"
windowWidth="800"
windowModalityType="modeless"
windowEmbedStyle="window"

Even though windowModalityType is stated as "modeless", new window opens as modal window.

I am using JDeveloper 11.1.1.7. I checked in forums and found others also are facing the same issue.

Can you point out, what is the correct way to display a modeless window?

Anonymous said...

Hi Dinesh,

I am having the same issue with windowModalityType="modeless". Please share your thoughts if you already have the solution.

Dinesh Chakravarthy said...

Hi,

Below is the solution to launch modeless window

1. Create a jspx page with the contents to be displayed in popup window
2. In the action listener of the link/button, invoke bean method, which has below code

public void launchPopupwindow(ActionEvent event)
{
//launch new window for revisions
FacesContext context = FacesContext.getCurrentInstance();
// Create the dialog UIViewRoot
ViewHandler viewHandler = context.getApplication().getViewHandler();
UIViewRoot dialog = null;
HashMap properties = new HashMap();
AdfFacesContext afContext = AdfFacesContext.getCurrentInstance();

properties.put("width", new Integer(850));
properties.put("height", new Integer(450));

dialog = viewHandler.createView(context, );

afContext.launchDialog(dialog, null,
// no particular parameters
null, // not launched from any component
true, //show in dialog
properties);

}

This will launch a seperate window for the defined dimensions

Anonymous said...

Dinesh,

Thanks for your quick reply. I have a requirement to open a new browser window that being populated with values from the Managed bean.


Does your solution works for non-static pages.

Dinesh Chakravarthy said...

Hi,

Yes. The solution works both for static and dynamic pages. Ensure the scope of the bean is properly defined.

with best regards,
Dinesh

Anonymous said...

Dinesh,

Thanks for your time. It worked

Regards
Suren.

Anonymous said...

Dinesh,

I have tried your solution and it worked. What if I want to open the same browser window instead of new browser window every time.

I have tried with following code also. But it is still open new window instead of open page in the exist window.

ExtendedRenderKitService erks =
Service.getRenderKitService(FacesContext.getCurrentInstance(),
ExtendedRenderKitService.class);
StringBuilder script = new StringBuilder();
script.append("window.open(\"" +
"/MyApp-ViewController-context-root/faces/newSearch.jspx + "\");");
erks.addScript(FacesContext.getCurrentInstance(), script.toString());

I appreciate your response.

Dinesh Chakravarthy said...

Hi,

Do you mean opening in a seperate tab in the same window or in the same tab?

If it is in same tab, then you have to navigate to different page using taskflows. If it is in seperate tab, try using af:showPopupBehavior. It will open the current window in a seperate tab. You have to explore ways to get your page using above two approaches.

Dinesh Chakravarthy said...

Correction in above post.

Use af:showPrintablePageBehavior to open the same page in seperate tab.

Apologies.