Saturday, November 5, 2011

Building Custom UI Shell with ADF 11g R2

ADF Task Flow support is improved in ADF 11g R2, now we have option to define multi task flow binding with dynamic number of regions - 21.10 Configuring a Page To Render an Unknown Number of Regions. This means we can implement our own UI Shell with dynamic tabs.

For UI demo, watch recorded video - it shows UI for sample application (MultiTaskFlowApp.zip). Each tab brings region from multi task flow binding, region can be removed/added together with tab as well as selected to be current. Multi task flow binding representation with tabs, is only one of the possible variants, you can implement other UI models as well. Ah and yes, in 11g R2 - tab close icon looks much better - it comes together with tab, just like for Web browsers.


Documentation explains how to render multiple regions and how to close selected region - 20.8.3 What You May Need to Know About Removing Navigation Tabs. Sample application is using described concepts, but provides more advanced functionality. Instead of using navigation pane component, we are generating dynamic tabs with for each operator. This operator is configured to retrieve information about rendered region from multi task flow binding:


Multi task flow binding points to managed bean, where we are constructing list of regions:


Tab removal is improved as well, instead of hiding closed tab - we are removing region itself from muti task flow binding list, this means tab will be removed without any additional action:


When menu item is selected, we want to make tab/region selected or open it, if it was closed. I have implemented custom method for this action:


Two custom helper methods from sample application. First method checks if tab/region is loaded. Second method makes tab/region to be selected:


31 comments:

  1. Hi
    Could you please help in one of ADF accordion implementation.
    I have a requirement to implement accordions on page. The scenario could be best explain with example: Lets say I have 3 tables schools, students, subjects. School contain list of schools. for each school there are number of students stored in students table and each student can enroll number of subjects. So, when user login in on page, depending upon school-ID,
    for each student in that school there would be an accordion component say student1, student2, student3 etc.. number of students-accordion will be dynamic based on number of students in that school. When student1 accordion is clicked, it should show all the subjects that student has enrolled. Similarly if student2- accordion is clicked it should corresponding list of subjects for that student.

    Any inputs or pointers on dynamic accordion. One approach would be iterate on number of students and create accordion accordingly..not sure it will work..

    Please send your response on my email: varunkgupta1@gmail.com.

    Thanks & Best Regards
    Varun

    ReplyDelete
  2. I'm not sure if I understand requirements, please drop me email @ gmail dot com

    Andrejus

    ReplyDelete
  3. Hi,
    how can we open new tab from another tab(region), not from created menu? Can not access pageFlowscope method(regionLaunch)to open new tab.
    Following your sample, let's try open departments in new tab from locations.

    Thanx,
    Patrik

    ReplyDelete
  4. Hi,

    You can create your bean with custom method, and generate Data Control on top of that bean. It will be accessible across all Task Flows (if not opened in Isolated scope).

    Hope this helps: http://andrejusb.blogspot.com/2012/01/data-control-and-session-scope-use-case.html

    Andrejus

    ReplyDelete
  5. Maybe I didn't explain it well. I don't need to open it in new browser tab, but in a new application tab(call another region). In your sample task-flows are being called by click on menu links, but if you try to call it from already opened region it fails.

    ReplyDelete
  6. No, I understood you correctly. What I was saying - is just example, you can use approach from provided blog sample to call Main method, which would open new application tab. You can apply same approach for your use case.

    The trick is - Data Control is shared across all Task Flows, and you can call methods without calling Session Scope.

    Andrejus

    ReplyDelete
  7. Thanx. I get the idea, but I can get it work :).

    I got NPE when try to call DataControl method which fires new tab/region.

    ReplyDelete
  8. Double check if your task flows are set to share data control (by default). May be its changed to Isolated?

    Andrejus

    ReplyDelete
  9. Data control share is ok. But stil same error. Not sure, but I believe that problem remains in pageFlowScope of mangaed bean, because taskflow list and varaibles are in that bean.

    ReplyDelete
  10. Yes, perhaps something is missing. Generally it should be possible. May be you should move out logic from your bean into Data Control class.

    Andrejus

    ReplyDelete
  11. Andrejus, in your projects which do you preffer fragments or pages? I'm stucked with a project and cannot decide which to use or which suites best to our requirements. Do you have any particular reason where and when to use fragments or/and pages?

    ReplyDelete
  12. Hi Patrik,

    Pages are good when system is smaller and menu model is not complicated (for example you open pages from central index page).

    Fragments are very good, when there are many ADF libraries and you need to integrate all together. Also its much easier to build menu model with Fragments, control pending changes during navigation, etc.

    Andrejus

    ReplyDelete
  13. Hi Andrejus,
    sorry for late response, but I was away for few days.
    Thanx very much for sharing your opinion about pages and fragments. This is excatly what I needed to confirm my ideas about our project. So we decide to split it in several pages as main categories/processes and fragments in those pages as subcategories/subprocesses.

    ReplyDelete
  14. Hi

    I'm using a slighty modified version of your example & it's working fairly well. The problem comes in when marking the tab as dirty. The following code isn't doing the job:



    If I use this in the parent component, it sets all tabs' text to italic.

    Do you have any suggestions?

    Another issue I'm getting is when attempting to close the last remaining tab - the handleCloseTabItem method isn't invoked, whereas it works for other tabs.

    ReplyDelete
  15. Thanks for sharing UI demo sample application.“Custom Browser Helper” Provides more advanced functionality in any Browsers.

    ReplyDelete
  16. Hi Andrejus,

    First, nice post.

    How do I hide all tabs for the first time applications launched? In your example, all tabs are shown in first loading of application.

    Thanks.

    ReplyDelete
  17. Hi,

    This is easy. Just modify Main bean - in constructor remove task flows added into mTaskFlowBindingAttrs.

    Regards,
    Andrejus

    ReplyDelete
  18. Hi Andrejus,
    In the regionOneLaunch method, you set id like this
    "tfAttr.setId(Locations)", and I understand that this is the label of panelTabbed.
    When I try to set a label with space it does not work. Do you know a way to achieve this? I want to set a label for the tab with spaces.

    ReplyDelete
  19. Hi,

    ADF API for this method unfortunately doesnt accept text with spaces. In my another project, I have additional method which I call from ADF UI get label by ID (labels are maintained in separate collection).

    Andrejus

    ReplyDelete
  20. Further to the post from Higor Fortunato regarding spaces in Tab labels, could you point me to an example of the approach you take in "my another project" that you refer to in your response to Higor?

    Also is there a way to make new Tabs appear as the last rather than the first tab?

    I have adapted your Custom UI Shell in an application I am developing and think it a terrific approach to the problem.

    John Hall

    ReplyDelete
  21. Yes, I was able to implement last tab to be selected by default. Actually we have developed our own template, where we handle tab labels, also last tab to be selected by default. Is not so easy to explain, it would require code posting, because its all in Java. May be in the future we will post it on the blog, for now we use it only in our projects as alternative for UI Shell template.

    For example, for the last tab - we always keep dummy invisible tab at the end and replace it with newly added tab and mark it selected. Dummy tab is shift to the right, this allows to mark last tab selected.

    Andrejus

    ReplyDelete
  22. This comment has been removed by the author.

    ReplyDelete
  23. Yes, this should work. You need to tabs behavior.

    Andrejus

    ReplyDelete
  24. Hi
    I have a requirement where in tab1 of pannel tabbed should call TF1 nd tab2 shd call TF2. Each of the task flows has a .jsff page which inturn has a method call which is invoked by a bean class. Both the .jsff method call r invoked from seperate bean class.
    Whn im running the app, instead of a particular bean class both the bean classes r being called. I just want one bean class to be called. Any suggestions!! (What logic shd i write in bean class so tht only one class is invoked whn a particular tab is pressed)

    ReplyDelete
  25. Hello Andrejus

    MultiTaskFlowApp is working fine.

    I created my own MultiTaskFlowApp and I did all thing like your app and when I run it that gives me following error:

    Error 500--Internal Server Error

    oracle.jbo.PersistenceException: JBO-29114 ADFContext is not setup to process messages for this exception. Use the exception stack trace and error code to investigate the root cause of this exception. Root cause error code is JBO-34000

    Please help me.

    Thanks & Best Regards
    Cho

    ReplyDelete
  26. Hi,

    Could you send your sample app to me by email, I will take a look - whats wrong.

    Regards,
    Andrejus

    ReplyDelete
  27. I am very new in Oracle ADF.Can we create dynamic tab without dynamic tab shell using?

    ReplyDelete
  28. Hi Andrejus, is there a way to do this in ADF 11g (prior R2).

    ReplyDelete