Ask a Jedi: Running code on Tab change with ColdFusion 8 Tabs

This post is more than 2 years old.

Rob Featherpants asks:

I'm building ColdFusion sites again after a while away, and I wonder if you can help me with a little advice about cflayoutarea and tabs. I am building a tabbed interface as part of a form. Outside of the tabs is a textarea, with its height set as an inline style. I want to change this height when one of the tabs is selected and set a cookie to remember which tab was last active ... i.e. have onClick on the tab trigger a Javascript. Can I do this?

Yep, you can, although it does take a few lines of JavaScript.

ColdFusion provides an API to get access to the underlying Ext based TabPanel object. You can get this object by running:

var mytabs = ColdFusion.Layout.getTabLayout('mytabs');

If you check the Ext docs for TabPanel, you will see there is an 'on' API call that lets you easily add event listeners. I used this:

mytabs.on('tabchange', function(tabpanel,activetab) { console.log('changed to a new tab '+activetab.getText()); })

The tabchange event passes the tabpanel object and the active tab. I defined a function that simply uses Firebug to log the text of the selected tab. Here is a complete example. Please note I use AjaxOnLoad to run the code to register the event:

<html>

<head> <script> function setup() { var mytabs = ColdFusion.Layout.getTabLayout('mytabs'); mytabs.on('tabchange', function(tabpanel,activetab) { console.log('changed to a new tab '+activetab.getText()); }) } </script> </head>

<body>

<cflayout type="tab" name="mytabs">

&lt;cflayoutarea title="Tab 1"&gt;
tab 1
&lt;/cflayoutarea&gt;

&lt;cflayoutarea title="tab 2"&gt;
tab 2
&lt;/cflayoutarea&gt;

</cflayout>

</body> </html>

<cfset ajaxOnLoad('setup')>

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Cliff Pearson posted on 12/2/2008 at 11:17 PM

Just a note of thanks Ray, as I had an enhancement ticket for the project I'm working on which required something very similar. Just after I'd marked the ticket 'will not fix', (as I didn't think I'd be able to do it), I spotted your post.

Quickly changed the status and an hour later, I had a very happy client.

Cheers!

</cliff>

Comment 2 by Rob posted on 12/3/2008 at 10:46 AM

Awesome Ray ... many thanks. This has got me started in the right direction.

This AJAX stuff is cool and adds great depth to CF, but of course there is much more to learn, as the black box tags only go so far.

Also, it seems that there are a lot of gotchas with the tags themselves. I don't seem to be able to use cfcalendar within my cfdivs, and cfinput and cftextarea validation is ignored, in spite of importing the tags into the calling page. A lot of trial and error ahead!

Comment 3 by Graham posted on 11/12/2009 at 7:15 PM

I don't entirely get this function. The part I don't get is where do the parameters for function(tabpanel,activetab) come from? Are they members of mytabs or do they have to be instantiated somewhere else?

Comment 4 by Raymond Camden posted on 11/12/2009 at 7:23 PM

That data is passed automatically by the event.

Comment 5 by Graham posted on 11/12/2009 at 9:06 PM

Thanks! Got everything working now.

Comment 6 by kd nyegaard posted on 8/23/2010 at 5:54 PM

Ray, I've tried replicating this code in CF9 and firebug tells me that .getText() is not found. Also, it does not work. Did the ext-js attributes change in CF9?

Comment 7 by Raymond Camden posted on 8/23/2010 at 6:00 PM

Yes. The version of Ext in CF9 is 3.something or another - much newer. Any code you wrote making use of Ext APIs needs to be updated.

Comment 8 by Jeremy posted on 1/21/2011 at 3:38 AM

Ray, I have an existing ajax function for each tab that refreshes the tab using setTimeout. I would like to run clearTimeout() when a user clicks off of a tab so that the timer does not continue to update information that is not even being viewed. Do you know how I could accomplish this?

Comment 9 by Raymond Camden posted on 1/21/2011 at 3:42 AM

Ah interesting. Let me rephrase your question to make sure I get it.

You have some func that runs every N seconds. You want it to work with the current tab. So if you switch tabs, the current interval should stop a new one should start.

Dumb q- why not use the same interval and have it check to see which tab is active?

Comment 10 by Jeremy posted on 1/21/2011 at 3:50 AM

Yes, that is correct on what I am doing.

I could use the same interval/function I suppose but how do I identify the active tab at any given moment?

Comment 11 by Raymond Camden posted on 1/21/2011 at 3:54 AM

It's been a while since I used CF's built in tabs. I coulda sworn there was a simple API to get it but I don't see it. Most likely it is simple if you call getTabLayout first. Let me do a quick test... but it will be for CF9. That ok? CF9 has a much newer Ajax library then 8 so if not - um - then I'll figure something else out. ;)

Comment 12 by Jeremy posted on 1/21/2011 at 3:57 AM

We are using CF8, but maybe what you come up with will still be viable?

I appreciate the assistance.

Comment 13 by Raymond Camden posted on 1/21/2011 at 4:03 AM

Found it:

http://www.johncblandii.com...

His blog is a bit hard to read - but you can see where he gets the 'active' tab.

Comment 14 by Jeremy posted on 1/21/2011 at 4:10 AM

Thanks! I will give this a shot.

Comment 15 by Jeremy posted on 1/21/2011 at 6:00 PM

Ray, while we are on the subject of Ajax refreshing, I wanted to run this by you as well. I am using jQuery 1.4.4 and use the .get API to check to see if I need to refresh data on a page or not. The problem is that there is a memory leak somewhere in the snippet below that I cannot seem to find. You will notice that I do a lot of potentially useless things here like deleting and add back the timer all in an effort to figure out what is going on. I assumed that doing the .load was causing the problem, but at this point, the .load doesn't occur very frequently at all. Anyway, if I can figure out this memory leak issue, I will be able to hook it up to the CF tablayout and should have a nice thing going. Hopefully you or somebody else can easily identify something silly I may be missing here.

<script>
$(document).ready(function() {
function CheckAlerts() {
//Must tell Ajax not to cache results
$.ajaxSetup({ cache: false });
$.get("AjaxDataCheck/CheckForDataRefresh.cfm", { datacheck: "MyAlerts"},
function(data) {
if (data.indexOf("true") >= 0) {
$.ajaxSetup({ cache: false });
$('#responsecontainer').load('alertchecking_Inner.cfm');
//Clearing the timer and recreating may force gargage collection.
clearTimeout(CheckAlertsTimer);
delete CheckAlertsTimer;
CheckAlertsTimer = setTimeout(CheckAlerts,2000);
}
else
{
//Clearing the timer and recreating may force gargage collection.
clearTimeout(CheckAlertsTimer);
delete CheckAlertsTimer;
CheckAlertsTimer = setTimeout(CheckAlerts,2000);
}
});
CheckAlertsTimer = setTimeout(CheckAlerts,2000);
};
CheckAlerts()
});
</script>

Thanks!

Comment 16 by Jeremy posted on 1/21/2011 at 9:29 PM

Something else to note. This code works great in Mozilla. No leaking at all.

Comment 17 by Raymond Camden posted on 1/22/2011 at 3:19 AM

Not really sure. My knowledge of JS doesn't really get into memory leaks.

Comment 18 by Chad posted on 3/10/2011 at 4:40 AM

Besides getText(), is there any other way to get the tabs name? I am just getting [object object] as my value when I set a form value using jQuery. I used a js for-in-loop, and can see the data I want but I don't know the js code to get that specific data. Thanks

Comment 19 by Raymond Camden posted on 3/10/2011 at 7:01 PM

If you see the data in a key called foo, and ob is the result of getText(), then just use ob.foo. It's just like CFML structures.

Comment 20 by Gregory Alexander posted on 8/14/2014 at 10:29 AM

Note: with CF 9 and higher, this function needs to be changed to:
function tabChangeListener(){
var mytabs = ColdFusion.Layout.getTabLayout('#tabName#');
mytabs.on('tabchange', doTabChange);
}

function doTabChange(){
var activeTabName = ColdFusion.Layout.getTabLayout('#tabName#').getActiveTab().title;

alert(activeTabName);
}

Comment 21 by Raymond Camden posted on 8/14/2014 at 2:33 PM

Thanks for sharing that update, Gregory.

Comment 22 (In reply to #21) by Gregory posted on 2/9/2015 at 7:30 AM

Thanks Raymond!
On another note- I am getting very annoyed having to deal with the code changes in the plumbing every time CF is updated with their Ajax controls and I am going to make the transition to some other grid system. I read your comments on some alternatives, but have you played with JqxWidets or Kendo UI? I like Kendo as I can keep a consistent look and feel for both Cf and .Net apps, but the coldFusion docs for Kendo are sparse.

Comment 23 (In reply to #22) by Raymond Camden posted on 2/10/2015 at 1:48 AM

I have not used JqxWidgets and I haven't *really" used Kendo UI, but I know many of the folks at Telerik and they are top notch. I'd check Kendo first. Not fair for me to say it is better than JqxWidgets, but I'd start there. If you have trouble, let me know. I can maybe hook you up with the right people.

Comment 24 (In reply to #22) by Jen Looper posted on 2/10/2015 at 3:33 PM

hi Gregory, Jen here from Telerik...if you have any questions about Kendo UI, please contact us on the Developer Relations team - I'm at jen.looper@telerik.com. You might also take a look at http://jqueryuiwidgets.com/ by Cody Lindley, also on our team.