Friday, June 13, 2008

Tabbed Regions in Oracle Apex using Extjs

David from Scotland emailed asking how I implemented tabbed regions on my demo site. 

It's actually very easy using Extjs.  

Step 1 - Create a region template which uses static ids  
<div id="#REGION_STATIC_ID#" class="tab-content">
<div class="x-fieldset-bwrap" style="padding:10px">
<div align="right" class="x-fieldset-tbar">#CLOSE##PREVIOUS##NEXT##DELETE##EDIT##CHANGE##CREATE##CREATE2##EXPAND##COPY##HELP#</div>
<div class="x-fieldset-body"> #BODY# </div>
</div>
</div>  

Step 2 - Create your report/form regions as usual, but assigning them a static id.
I tend to use tab1, tab2, ..., tabn - but that's a personal choice.

Step 3 - Add an opening div tag before the first tab region and a closing div tag after the last region. <div id="pageTabs"> </div>
You can either create extra regions of type "html text" with no template, or simply add the extra tags in your region header and region footer. I use extra regions, so it's really obvious whats going on when I look at again in 6 months time. When the page is generated the html will look like this:
<div id="pageTabs">
    <div id="tab1" class="tab-content"> <!-- content --> </div> 
    <div id="tab2" class="tab-content"> <!-- content --> </div> 
    <!-- and so on -->
    <div id="tabn" class="tab-content"> <!-- content --> </div>
</div> 

Step 4 - Add the javascript magic Here I'm showing 2 tabs, and usually include the script with the closing div tag.
<script type="text/javascript">
Ext.onReady(function(){
       var tabs = new Ext.TabPanel({
           cls: 'prism',
           applyTo: 'pageTabs',
           plain: true,
           width: 795,
           //height: 450,
           autoHeight:true,
           enableTabScroll:true,
           autoScroll:true,
           activeTab: 0,
           deferredRender: false,
           border: true,
           defaults: {layout:'fit', autoScroll:true},
           items:[
               {contentEl:'tab1', title:'Create/Edit Customer'},
               {contentEl:'tab2', title:'Existing Customers'}
           ]
           });
});
</script>

The cls: 'prism' is a customisation I use to have a blue background for the tab panel.
I'll leave that for you to work out how I did that.

As usual, the documentation on tab panels goes into far more details. Mark

31 comments:

Anonymous said...

Very Nice work.

Anonymous said...

Many thanks for that mark

Anonymous said...

Mark this is a sweet technique. I was hoping someone might put out the instructions on how it works. I am gonna try this soon. Thanks again!

Unknown said...

Hi, I tried to integrate this simple solution but firebug gives me the following java script error

Ext is not defined
Ext.onReady(function(){

Do I have to put the script within the --> close tab /div tag?

I am using apex 3.0

thanks

Mark Lancaster said...

Hi David

"Ext is not defined" usually happens if you haven't included the ext libraries in your page template.

See my earlier post http://oracleinsights.blogspot.com/2008/02/integrating-ext-javascript-library-into.html for integration details

Anonymous said...

Thank you for your informative blog. How do you link the report to display the form when the edit icon is selected on any row? Keep up the good work.

Mark Lancaster said...

Hi Meyer

I'm using standard Apex functionality for the edit icon.

The page is just a report region and a form region.
The report has a column link which calls the same page passing the customer_id.

e.g.

http://apex.oracle.com/pls/otn/f?p=200801:2005:4231872663693000::::P2005_CUSTOMER_ID:26546

Mark

Anonymous said...

Mark,
Is it possible to have more than two tabs and then change the active tab with the column link as previously described, i.e. have a customer address report region on another tab and a customer address edit form on another region within the same tabpanel.
When the user selects an address from the report region then the address edit form should be displayed. This means the page will contain four tabs with two report and two form regions.
Thanks again.
Meyer

Mark Lancaster said...

Hi Meyer

Yes it is.

Refer to the doco on activeTab and setActiveTab.

You just need to work out your logic and generate the javascript.

Anonymous said...

I do appreciate your work and your samples of you interfacing APEX and JavaScript using Extjs. I am having a problem getting the "tabbed region" up and running. I have spent hours and hours working on it, but for some reason, I'm not connecting the dots.

I have followed your suggestions as closely as I could, but I am still unable to make it work.

I posted a question on the APEX forum in hopes of a solution, but so far, none quite yet. I am pasting the link to the thread, if you get a chance, could you take a look at it and see if you can offer some suggestions/help. I hate asking, but your solution is clearly the one for my application, and if only I could get this sample up and running, I would sign on full speed!

Look at the thread below, and please give me some advice.

Thanks,

Charles

http://forums.oracle.com/forums/thread.jspa?threadID=829375&tstart=0

Cj (Bar Staff) said...

Hi Mark,

Thanks for your excellent post on Tabbed Regions. I have been following it through and my tabs are working excellently.

I did have a question though around the tabs when the page initially loads. Firstly the page is displayed with the "tabbed" regions as their separate ApEx regions, the onReady JS then kicks in and formats them properly as a single tabbed panel.

The only way I can see of preventing the user from seeing this transition is to use a Page Loading icon, similar to the one you have when you first navigate to your site.

Do you have an example of how to do this, I have tried several searches on the Internet, and they don't seem to work exactly as expected.

Any other advise on how to solve this issue would be greatly appreciated.

I look forward to hearing from you.

Kindest Regards,

Chris

Ron said...

Mark this is a great tut. I was able to implement it without any issues. Is it possible to embed multiple regions within each tab? I need to embed four apex charts on Tab1 and two reports on Tab2. Would you know how to go about to accomplish this.

Mark Lancaster said...

Hi Ron

Simple enough to implement.
Just use a different region template, and add the "tab" divs manually in the appropriate "before region" and "after region" sections.

Just think "How would I do this in the page, and not the template".

Regards

Mark

Ron said...

Brilliant. It works. Thanks Mark.

Anonymous said...

I have had some unpredictable results with updateable fields using the extjs tabbed regions. Lost updates. May just be me but proceed with caution.

Mark Lancaster said...

Hi Anonymous

If your having unpredictable results with ExtJS tabs, then your definitely doing something wrong.

Something you need to watch out for when using JavaScript to manipulate your page layout, is that you can move form items outside the form element.

This is regardless of what framework, be it ExtJS, jQuery, YUI, Dojo or any other framework.

How do you stop this happening?

In Ext you can use allowDomMove:false, on a case by case basis.

I solved it once and for all by using a customized viewport, which makes the form element the viewport - all page elements are contained within it.

See this post http://oracleinsights.blogspot.com/2009/04/extjs-customized-viewport-for-oracle.html

Regards

Mark

Anonymous said...

Mark,
Thanks for this good work.

With out step 1 also your tab is working.
If Step one is required , where i have to put all these DIV tags of step1

and also Could you please explain in little detail how to embade multiple regions in single tab.

Thank a lot

Khalid
Mu

Mark Lancaster said...

Hi Kalid

Step 1 is only for styling the region template, you could use a simple div instead also.

To include multiple regions in a single tab, just add a div wrapper around the regions you want to enclose and reference this instead.

Anonymous said...

Mark,
Thanks you so much. Multiple reports in single tab is working.
By Default Reports displaying vertically in a single tab,Any Idea How to arrange reports in a single tab side by side.
and How to control the alignment.

i guess this needs some kind of CSS properties to be applied on DIV tag

Appreciate your help.

Regards
Khalid.

ERP systems said...

Hi Mark,
is there any extended examples how u creating this FORM/REPORT or more detail way how to set static_id?
I was creating
Step 1 - Create a region template which uses static ids
(I was creating one region)

Step 2 - Create your report/form regions as usual, but assigning them a static id.


Step 3 - Add an opening div tag before the first tab region and a closing div tag Where is this tag need placed and in with html will be generated code?
Step 4 I was add java script into images
and set link to that(and do same with ext-all.js, ext-all.css, and ext-base.js Ext js 2.2 version)

but my example dont work
Gordan

Mark Lancaster said...

Hi Gordon

You add the closing tab in either:
- the region footer of your last tab region
- an extra region after the last region you are including.

i.e. you are wrapping a DIV around the regions you want to be tabbed.

The static id is assigned in APEX attributes for the region - look for the field "Static Id".

I would strongly encourage you to update from ExtJS 2.2 to the latest version (currently 3.2).

Also, implementing tabs is much easier in APEX 4.0 - using same principles but with nested regions and templates to generate your JS.

Mark

ERP systems said...

Hi Mark, I was trying to creating step 1,2,3 and this examples have double tabed regions
http://apex.oracle.com/pls/otn/f?p=21298:2

I was creating Regions Edit AllCopyCreate
Display Point: Page Template Body (3)Reorder Regions
10 Edit CUSTOMERS HTML
20 REPORT Report
30 Tabs close HTML

Display Point: Region Position 01
1 Breadcrumbs Breadcrumb Entry
and set in Tabs close div id PageTabs with /div.
I was creating Ragion Template (above step 1)+ code and put ext-all.js, ext-all.css, and ext-base.js Ext js 2.2 version-stil but will change to 3.2.
Other thing is stability of this kind of forms/reports in production phases?
Gordan

Mark Lancaster said...

Gordon

Look at your page source - you've called the tab function twice!

On stability - I have been using this successfully in production for over 3 years without any issues.
All it's doing is manipulating html.

Enrico said...

Hi Mark, first of all this post is great so thanks a lot.
I have the same issue of Khalid.
I could put 2 regions (a report and a graph) in the same TAB but I'm not able to display them side by side.
Is there a "trick"?

Best Regards!
Enrico

Mark Lancaster said...

Hi Enrico

Haven't done it myself, but I would take the following approach.

1. Create APEX page with 2 regions side-by-side.
This is done by setting the right-hand region to have the same sequence value, and set column value to 2 in the region User Interface section.

2. Add tab DIV tags manually around regions instead of using custom template, checking DIV open tag is before the LH region, and DIV close tag after RH region.
Depending on what HTML APEX has generated, you may need to make further adjustments.
For example, need to wrap 2 regions with a table open, table close first.

If that approach doesn't pan out, you could try:
- in APEX 4 including the chart as a sub-region, and use a CSS rule to float: right
- reposition the chart using JavaScript.

Hope this helps.

Mark

Anonymous said...

Mark thanks a lot for the fast answer and suggestions.
Unfortunatly setting the column value to 2 (for the right side region) it seems the div tag doesn't apply to it and so the region is outside the "tab" on the real right of the screen even adding table open/close.
I'll try to manage the position in other ways (javascript as you suggest).
Thanks anyway Mark!
Enrico

Enrico said...

Mark I got it! :)
Your suggestion was ok but not being HTML expert probably I applied it wrong.

The HTML region before the two regions (left and right regions of the tab0) should contain:
div id="tab0"
table
tr

Then the 2 regions of the tab (a report and a graph in my case) should be both with the attribute column set to 1; the sequence determines the left region and the right one. Both the graph and the report have to be contained in td tag (so in the HTML header of both let's put td and in the HTML footer let's put /td).

Finally I placed a HTML region after the left and the right region:
/tr
/table
/div

After that it works fine.
Thanks again Mark. Your job is amazing.
Enrico

Mark Lancaster said...

Hi Enrico

Glad it worked out for you.

Mark

Anonymous said...

Hi Mark, Quick question regarding tabs please. I have a Page(#1) which has 4 tabs as a,b,c,d. I am navigating from Page(#2) to Page(#1) and I want to land on D tab. Just to re-phrase I am navigating to Page 1 from different places and each time I want to land on a Specific tab. Please help me.

Mark Lancaster said...

Hi Anon

As per earlier comments, refer to the doco on activeTab and setActiveTab.

I would set a page item value to the tab number you want active, and include JS to set the active tab based on that value.

Ext tabs are zero based, so to set the active tab to be the second tab you would set it to 1.

The modified blog code (untested) to pick up a page item P99_ACTIVE_TAB value:

Ext.onReady(function(){
var tabs = new Ext.TabPanel({
cls: 'prism',
applyTo: 'pageTabs',
plain: true,
width: 795,
//height: 450,
autoHeight:true,
enableTabScroll:true,
autoScroll:true,
activeTab: $v('P99_ACTIVE_TAB') || 0,
deferredRender: false,
border: true,
defaults: {layout:'fit', autoScroll:true},
items:[
{contentEl:'tab1', title:'Create/Edit Customer'},
{contentEl:'tab2', title:'Existing Customers'}
]
});
});

Regards

Mark

Anonymous said...

Hi Mark,

i was trying to set the Tab-Title (of a sub region) from within APEX depending on business logic.
The &var_title. scheme doesn't work.
Am i missing sometthing?
I read several posts on the internet dealing with "pure APEX" environments and talking about workarounds, but that did not help me in my EXTJS environment.
best regards
Jochen