jQuery UI Tabs - How to Get Currently Selected Tab Index - javascript

I know this specific question has been asked before, but I am not getting any results using the bind() event on the jQuery UI Tabs plugin.
I just need the index of the newly selected tab to perform an action when the tab is clicked. bind() allows me to hook into the select event, but my usual method of getting the currently selected tab does not work. It returns the previously selected tab index, not the new one:
var selectedTab = $("#TabList").tabs().data("selected.tabs");
Here is the code I am attempting to use to get the currently selected tab:
$("#TabList").bind("tabsselect", function(event, ui) {
});
When I use this code, the ui object comes back undefined. From the documentation, this should be the object I'm using to hook into the newly selected index using ui.tab. I have tried this on the initial tabs() call and also on its own. Am I doing something wrong here?

If you need to get the tab index from outside the context of a tabs event, use this:
function getSelectedTabIndex() {
return $("#TabList").tabs('option', 'selected');
}
Update:
From version 1.9 'selected' is changed to 'active'
$("#TabList").tabs('option', 'active')

For JQuery UI versions before 1.9: ui.index from the event is what you want.
For JQuery UI 1.9 or later: see the answer by Giorgio Luparia, below.

If you're using JQuery UI version 1.9.0 or above, you can access ui.newTab.index() inside your function and get what you need.
For earlier versions use ui.index.

UPDATE [Sun 08/26/2012] This answer has become so popular that I decided to make it into a full-fledged blog/tutorial
Please visit My Blog Here to see the latest in easy access information to working with tabs in jQueryUI
Also included (in the blog too) is a jsFiddle
¡¡¡ Update! Please note: In newer versions of jQueryUI (1.9+), ui-tabs-selected has been replaced with ui-tabs-active. !!!
I know this thread is old, but something I didn't see mentioned was how to get the "selected tab" (Currently dropped down panel) from somewhere other than the "tab events".
I do have a simply way ...
var curTab = $('.ui-tabs-panel:not(.ui-tabs-hide)');
And to easily get the index, of course there is the way listed on the site ...
var $tabs = $('#example').tabs();
var selected = $tabs.tabs('option', 'selected'); // => 0
However, you could use my first method to get the index and anything you want about that panel pretty easy ...
var curTab = $('.ui-tabs-panel:not(.ui-tabs-hide)'),
curTabIndex = curTab.index(),
curTabID = curTab.prop("id"),
curTabCls = curTab.attr("class");
// etc ....
PS. If you use an iframe variable then .find('.ui-tabs-panel:not(.ui-tabs-hide)'), you will find it easy to do this for selected tabs in frames as well.
Remember, jQuery already did all the hard work, no need to reinvent the wheel!
Just to expand (updated)
Question was brought up to me, "What if there are more than one tabs areas on the view?"
Again, just think simple, use my same setup but use an ID to identify which tabs you want to get hold of.
For example, if you have:
$('#example-1').tabs();
$('#example-2').tabs();
And you want the current panel of the second tab set:
var curTabPanel = $('#example-2 .ui-tabs-panel:not(.ui-tabs-hide)');
And if you want the ACTUAL tab and not the panel (really easy, which is why I ddn't mention it before but I suppose I will now, just to be thorough)
// for page with only one set of tabs
var curTab = $('.ui-tabs-selected'); // '.ui-tabs-active' in jQuery 1.9+
// for page with multiple sets of tabs
var curTab2 = $('#example-2 .ui-tabs-selected'); // '.ui-tabs-active' in jQuery 1.9+
Again, remember, jQuery did all the hard work, don't think so hard.

var $tabs = $('#tabs-menu').tabs();
// jquery ui 1.8
var selected = $tabs.tabs('option', 'selected');
// jquery ui 1.9+
var active = $tabs.tabs('option', 'active');

When are you trying to access the ui object? ui will be undefined if you try to access it outside of the bind event.
Also, if this line
var selectedTab = $("#TabList").tabs().data("selected.tabs");
is ran in the event like this:
$("#TabList").bind("tabsselect", function(event, ui) {
var selectedTab = $("#TabList").tabs().data("selected.tabs");
});
selectedTab will equal the current tab at that point in time (the "previous" one.) This is because the "tabsselect" event is called before the clicked tab becomes the current tab. If you still want to do it this way, using "tabsshow" instead will result in selectedTab equaling the clicked tab.
However, that seems over-complex if all you want is the index. ui.index from within the event or $("#TabList").tabs().data("selected.tabs") outside of the event should be all that you need.

this changed with version 1.9
something like
$(document).ready(function () {
$('#tabs').tabs({
activate: function (event, ui) {
var act = $("#tabs").tabs("option", "active");
$("#<%= hidLastTab.ClientID %>").val(act);
//console.log($(ui.newTab));
//console.log($(ui.oldTab));
}
});
if ($("#<%= hidLastTab.ClientID %>").val() != "")
{
$("#tabs").tabs("option", "active", $("#<%= hidLastTab.ClientID %>").val());
}
});
should be used. This is working fine for me ;-)

In case anybody has tried to access tabs from within an iframe, you may notice it's not possible. The div of the tab never gets marked as selected, just as hidden or not hidden. The link itself is the only piece marked as selected.
<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-focus">Tab 5</li>
The following will get you the href value of the link which should be the same as the id for your tab container:
jQuery('.ui-tabs-selected a',window.parent.document).attr('href')
This should also work in place of: $tabs.tabs('option', 'selected');
It's better in the sense that instead of just getting the index of the tab, it gives you the actual id of the tab.

the easiest way of doing this is
$("#tabs div[aria-hidden='false']");
and for index
$("#tabs div[aria-hidden='false']").index();

In case if you find Active tab Index and then point to Active Tab
First get the Active index
var activeIndex = $("#panel").tabs('option', 'active');
Then using the css class get the tab content panel
// this will return the html element
var element= $("#panel").find( ".ui-tabs-panel" )[activeIndex];
now wrapped it in jQuery object to further use it
var tabContent$ = $(element);
here i want to add two info the class .ui-tabs-nav is for Navigation associated with and .ui-tabs-panel is associated with tab content panel. in this link demo in jquery ui website you will see this class is used - http://jqueryui.com/tabs/#manipulation

I found the code below does the trick. Sets a variable of the newly selected tab index
$("#tabs").tabs({
activate: function (e, ui) {
currentTabIndex =ui.newTab.index().toString();
}
});

$( "#tabs" ).tabs( "option", "active" )
then you will have the index of tab from 0
simple

You can post below answer in your next post
var selectedTabIndex= $("#tabs").tabs('option', 'active');

Try the following:
var $tabs = $('#tabs-menu').tabs();
var selected = $tabs.tabs('option', 'selected');
var divAssocAtual = $('#tabs-menu ul li').tabs()[selected].hash;

You can find it via:
$(yourEl).tabs({
activate: function(event, ui) {
console.log(ui.newPanel.index());
}
});

Another way to get the selected tab index is:
var index = jQuery('#tabs').data('tabs').options.selected;

$("#tabs").tabs({
load: function(event, ui){
var anchor = ui.tab.find(".ui-tabs-anchor");
var url = anchor.attr('href');
}
});
In the url variable you will get the current tab's HREF / URL

take a hidden variable like '<input type="hidden" id="sel_tab" name="sel_tab" value="" />' and on each tab's onclick event write code like ...
<li><a href="#tabs-0" onclick="document.getElementById('sel_tab').value=0;" >TAB -1</a></li>
<li><a href="#tabs-1" onclick="document.getElementById('sel_tab').value=1;" >TAB -2</a></li>
you can get the value of 'sel_tab' on posted page. :) , simple !!!

If you want to ensure ui.newTab.index() is available in all situations (local and remote tabs), then call it in the activate function as the documentation says:
$("#tabs").tabs({
activate: function(event, ui){
alert(ui.newTab.index());
// You can also use this to set another tab, see fiddle...
// $("#other-tabs").tabs("option", "active", ui.newTab.index());
},
});
http://jsfiddle.net/7v7n0v3j/

$("#tabs").tabs({
activate: function(event, ui) {
new_index = ui.newTab.index()+1;
//do anything
}
});

Related

is this an acceptable use of jquery data()?

I'm using jquery data() to attach the name of a div I'd like to show when another div (.panel_button) is clicked. I'm doing the attaching of this div's id to the button when the document is ready. Is this an okay way to do this? Or is it too resource intensive and unprofessional-looking?
$(document).ready(function(){
$('#sample_button').data('panel', 'sample_kit_container');
$('#mail_button').data('panel', 'mail_container');
$('#mbillboard_button').data('panel', 'mbillboard_container');
$('.panel_button').on('click', function(){
$('.secondary_panel').hide();
var panel = $(this).data('panel');
$('#' + panel).show();
});
});
Yeah, that should work just fine. As an alternate, you could store the actual element itself (assuming it already exists) rather than finding it each time:
$('#sample_button').data('panel', $('#sample_kit_container'));
$('#mail_button').data('panel', $('#mail_container'));
$('#mbillboard_button').data('panel', $('#mbillboard_container'));
$('.panel_button').on('click', function(){
$('.secondary_panel').hide();
var panel = $(this).data('panel');
panel.show();
});
Another option would be to store the actual jQuery element in the data property, so no need to do a second selection:
$(function(){
$('#sample_button').data('panel', $('#sample_kit_container'));
$('#mail_button').data('panel', $('#mail_container'));
$('#mbillboard_button').data('panel', $('#mbillboard_container'));
$('.panel_button').on('click', function(){
$('.secondary_panel').hide();
var panel = $(this).data('panel');
panel.show();
});
});
#thomas, in my opnion, your solution is actually better than those in the other answers.
Including the whole object inside the data attribute may not always work. For example, what if the $('#sample_kit_container') object doesn't exist on load, but rather ofter an ajax load.
...
Only one tiny comment! why don't you call the data object: panelId. It would be more a bit intuitive.

jQuery Tipsy won't work with jQuery.each() and live:true

Note: This question was marked as solved once, but it figured out that upgrading to the latest jQuery was fixed only one issue. Please see the updated question below for the remaining issue.
Hi all,
I have just run into a weird issue with jQuery.Tipsy.
Here's a simplified demo fiddle: http://jsfiddle.net/6nWtx/7/
As you can see, the lastly added a.tipsy2 element does not get tipsyfied. The .tipsy2 elements are being tipsyfied within a jQuery.each() function and at this point I have the problem. Without the each() it works. Unfortunately, I need .each() to iterate through the elements to do some other stuff before I call tipsy().
Any suggestion?
Here's the source code of Tipsy: https://github.com/jaz303/tipsy/blob/master/src/javascripts/jquery.tipsy.js
IMHO the problem is using the combination of jQuery.each() and Tipsy option live:true
Update:
The other stuff I want to do before calling .tipsy() is checking for some optional configuration.
For example: Help"
In this example I will add the following option to Tipsy: delayIn:1000 If there is no delayed class associated to the element this parameter will be delayIn:0.
Using the same logic, I want to specify the following classes as well: show-top, show-left, show-right, show-bottom for the Tipsy option called gravity.
Example: Help"
The full code:
$(".tipsyfy").each(function () {
var a = "s",
b = 0;
if ($(this).hasClass("show-left")) a = "w";
else if ($(this).hasClass("show-down")) a = "n";
else if ($(this).hasClass("show-right")) a = "e";
if ($(this).hasClass("delayed") && $(this).attr("data-delayIn") != null) b = $(this).attr("data-delayIn");
$(this).tipsy({
gravity: a,
fade: true,
live: true,
delayIn: b
})
})
And here is a full jsFiddle demo with all the stuffs I want to do: http://jsfiddle.net/xmLBG/1/
If you use jQuery 1.7.1 instead of 1.6.4 it will work. Maybe that live feature is relying on something buggy with the older versions, or some not-yet-implemented feature.
Update: from what I understood, you want the tipsy plugin to be called to every element with the .tipsyfy class, present now or added in the future. You don't want to (or can't) call it explicitly before insertion. You're trying to accomplish that using the live option of the plugin. Is that right?
If that's the case I can offer a workaround. I tried to use on (since jQuery's live is deprecated) to bind some code to the load event, but it didn't work, so I bound it to mouseenter and checked whether or not the plugin was already built for that element. If not, it builds it and re-triggers the event.
$(document).on("mouseenter", ".tipsyfy", function(e) {
if ( !$(this).data("tipsy") ) {
e.preventDefault();
var a = "s",
b = 0;
if ($(this).hasClass("show-left")) a = "e";
else if ($(this).hasClass("show-down")) a = "n";
else if ($(this).hasClass("show-right")) a = "w";
if ($(this).hasClass("delayed") && $(this).attr("data-delayIn") != null) b = $(this).attr("data-delayIn");
$(this).tipsy({
gravity: a,
fade: true,
live: true,
delayIn: b
}).trigger("mouseenter");
return false;
}
});
Live example at jsFiddle.
For a small optimization, if the sole purpose of the .tispsyfy class is to instruct the plugin creation, and you don't need it afterwards, you can remove it prior to re-triggering the mouseenter. This way the checking code won't be called over and over again:
$(this).tipsy({...}).removeClass("tipsyfy").trigger("mouseenter");
As far as I can see, you don't need to iterate the nodelist. It looks like tipsy does that for you (see this jsfiddle, where in the first list every element gets its own tooltip (1,2,3).
KooiInc is right,
<a class="tipsy1" href="#" title="Tipsy">TipsyLink</a>
<a class="tipsy1" href="#" title="Tipsy">TipsyLink</a>
<a class="tipsy1" href="#" title="Tipsy">TipsyLink</a>
<br />
<div id="container"></div>
<input id="add" type="button" value="ok">
And
$(".tipsy1").tipsy({live:true,fade:true});
$(".tipsy2").tipsy({live:true});
$("#add").click(function() {
$("#container").append('<a class="tipsy2" href="#" title="Tipsy">TipsyLink</a>');
});
That will work fine
My guess is that Tipsy are uses some kind of direct mapping to the result, not using the live (in 1.6) or on in newer versions of jQuery.
So when your trying to apply the plugin to the links with the class tipsy2 it cant find any (cause your adding it to the DOM at a later stage in your code). The easiest fix to this is just to run the tipsy function at a later stage, perhaps on document.ready.
// this works
$(".tipsy1").tipsy({live:true,fade:true});
// add new tipsy element (ok)
$(document.body).append('<a class="tipsy1" href="#" title="TipsyAjax">AjaxTipsy1</a><br/>');
// add new tipsy element (not ok)
$(document.body).append('<a class="tipsy2" href="#" title="Tipsy">TipsyLink</a>');
$(document).ready(function () {
$(".tipsy2").each(function(){
// I'm doing some other logic here before I call .tipsy()
$(this).tipsy({live:true,fade:true});
})
});
(http://jsfiddle.net/8dg6S/7/)
Can't you do this instead? It is what you are asking.
$(".tipsy1,.tipsy2").tipsy({live:true,fade:true});
$(".tipsy2").each(function() {
//do your stuff
});

How do I run a jQuery function when any link (a) on my site is clicked

I have a new site build on corecommerce system which does not have much access to HTML and non to PHP. Only thing I can use is JavaScript. Their system is currently not great on page load speed so I wanted at least customers to know something is happening while they wait 5-8 seconds for a page to load. So I found some pieces of code and put them together to show an overlay loading GIF while page is loading. Currently it will run if you click anywhere on the page but I want it to run only when a link (a href) on the site is clicked (any link).
I know you can do a code that will run while page loading but this isn't good enough as it will execute too late (after few seconds)
Anyway, this is my website www.cosmeticsbynature.com and this is the code I use. Any help will be great.
<div id="loading"><img src="doen'tallowmetopostanimage" border=0></div>
<script type="text/javascript">
var ld=(document.all);
var ns4=document.layers;
var ns6=document.getElementById&&!document.all;
var ie4=document.all;
if (ns4)
ld=document.loading;
else if (ns6)
ld=document.getElementById("loading").style;
else if (ie4)
ld=document.all.loading.style;
jQuery(document).click(function()
{
if(ns4){ld.visibility="show";}
else if (ns6||ie4)
var pb = document.getElementById("loading");
pb.innerHTML = '<img src="http://www.cosmeticsbynature.com/00222-1/design/image/loading.gif" border=0>';
ld.display="block";
});
</script>
Doing this will be easier if you include jQuery in your pages. Once that is done, you can do:
$('a').click(function() {
// .. your code here ..
return true; // return true so that the browser will navigate to the clicked a's href
}
//to select all links on a page in jQuery
jQuery('a')
//and then to bind an event to all links present when this code runs (`.on()` is the same as `.bind()` here)
jQuery('a').on('click', function () {
//my click code here
});
//and to bind to all links even if you add them after the DOM initially loads (`on()` is the same as `.delegate()` here; with slightly different syntax, the event and selector are switched)
jQuery(document).on('click', 'a', function () {
//my click code here
});
Note: .on() is new in jQuery 1.7.
what you are doing is binding the click handler to the document so where ever the user will click the code will be executed, change this piece of code
jQuery(document).click(function()
to
jQuery("a").click(function()
$("a").click(function(){
//show the busy image
});
How about this - I assume #loading { display:none}
<div id="loading"><img src="http://www.cosmeticsbynature.com/00222-1/design/image/loading.gif" border=0></div>
<script type="text/javascript">
document.getElementById('loading').style.display='block'; // show the loading immediately
window.onload=function()
document.getElementById('loading').style.display='none'; // hide the loading when done
}
</script>
http://jsfiddle.net/vol7ron/wp7yU/
A problem that I see in most of the answers given is that people assume click events only come from <a> (anchor) tags. In my practice, I often add click events to span and li tags. The answers given do not take those into consideration.
The solution below sniffs for elements that contain both events, which are created with jQuery.click(function(){}) or <htmlelement onclick="" />.
$(document).ready(function(){
// create jQuery event (for test)
$('#jqueryevent').click(function(){alert('jqueryevent');});
// loop through all body elements
$('body *').each(function(){
// check for HTML created onclick
if(this.onclick && this.onclick.toString() != ''){
console.log($(this).text(), this.onclick.toString());
}
// jQuery set click events
if($(this).data('events')){
for (key in($(this).data('events')))
if (key == 'click')
console.log( $(this).text()
, $(this).data('events')[key][0].handler.toString());
}
});
});
Using the above, you might want to create an array and push elements found into the array (every place you see console.log

How to hide/close other elements when new element is being opened?

Ran into problem with creating custom select dropdown plugin in jQuery. I'm at the one-at-the-time-open feature. Meaning, that when you open a dropdown, then other(s) will close.
My first idea was to create some global array with all dropdowns in it as objects. Then in the "opening"-function, I would add the first line to first check that none of the dropdowns are open (if open, then close them.)
I created a very scaled version of my script: http://jsfiddle.net/ngGGy/1/
Idea would be to have only one dropdown open at the time. Meaning, that when you open one, other(s) must be closed, if not they will automatically close when a new one is opened.
Your dropdown set seems to behave like an accordion.
This is easier to accomplish if you wrap each dropdown in a div with a class, then use that to target all the dropdown uls you have.
I forked your jsfiddle with a working example.
(EDIT updated fiddle link)
You can keep track of the DropDownSelectized lists like this: http://jsfiddle.net/pimvdb/ngGGy/3/.
(function($){
var lists = $(); // cache of lists
$.fn.DropDownSelect = function (settings) {
jQuery.globalEval("var zindex = 100");
var thiselement = $(this);
var thislist = thiselement.next('ul');
lists = lists.add(thislist); // add current one to cache
thiselement.click(function () {
lists.slideUp(); // hide all lists initially
if (thislist.is(':visible')) {
thislist.slideUp();
} else {
thislist.css('z-index', ++zindex).slideDown();
}
});
};
})(jQuery);
You're definitely on the right track, but if you're only going to have one dropdown list open at a time then you want them to be related somehow. Fortunately your markup is already there, so all we should have to do is modify the JS. I've updated your jsFiddle project here: http://jsfiddle.net/ninjascript/ngGGy/4/
First the selector. jQuery will let you select attributes that are similar by using ^= like this:
$('div[id^=button]').DropDownSelect();
Now we just have to update your plugin a bit. Notice that what used to be 'thislist' is now called 'everylist'. Now we can enforce that every list closes on click before opening the list associated with the button that was clicked.
(function($){
$.fn.DropDownSelect = function (settings) {
jQuery.globalEval("var zindex = 100");
var thiselement = $(this);
var everylist = thiselement.next('ul');
thiselement.click(function () {
var thislist = $(this).next('ul');
if (everylist.is(':visible')) {
everylist.slideUp();
}
thislist.css('z-index', ++zindex).slideDown();
});
};
})(jQuery);
Good luck!
Why not raise an event that all drop-downs subscribe to. pass in the id (or instance) of the one currently being opened. In the handler check whether the handling instance is the one being opened. If not, close it.

JQuery Async postback issue, how do I fix this?

I have the following JQuery code which does similar functionality like Stackoverflow where the user clicks on the comment link and it displays the comments or in this case replies to a member's status update, generally it works great except when a member posts a new status update which updates the list of status updates using an ajax async postback in ASP.net MVC.
What happens is if you click on the new item in the list it brings them to a new page instead of doing what the JQuery is suppose to do.
<script type="text/javascript">
$(function() {
$("a[id ^='commentLink-']").click(function() {
match = this.id.match(/commentLink-(\d+)/);
container = $("div#commentContainer-" + match[1])
container.toggle();
if (container.is(":visible")) {
container.load($(this).attr("href"));
} else {
container.html("Loading...");
}
return false; //Prevent default action
});
});
</script>
Note: I think what is causing it is the fact that the new item in the list isn't actually on the page as the list was updated through the ajax so the new html isn't there until the page is refreshed.
Update Okay how would I use this live/event functionality that Paolo Bergantino spoke of in his answer to trigger an ASP.net MVC ActionResult?
Check out the new Events/live feature in jQuery 1.3
Binds a handler to an event (like click) for all current - and future - matched element.
So as you add new items, jQuery should add the click event to them with this.
If for some odd reason you do not want to upgrade to jQuery 1.3, you can check out the livequery plugin.
EDIT in response to update:
The actual code to use .live would be something like this:
$(function() {
$("a[id ^='commentLink-']").live('click', function(event) {
match = this.id.match(/commentLink-(\d+)/);
container = $("div#commentContainer-" + match[1])
container.toggle();
if (container.is(":visible")) {
container.load($(this).attr("href"));
} else {
container.html("Loading...");
}
event.preventDefault();
});
});
The changes that were made are mostly in the 2nd line, where
$("a[id ^='commentLink-']").click(function() {
was replaced by
$("a[id ^='commentLink-']").live('click', function(event) {
I am now also receiving the argument event to use for event.preventDefault(); which is the way you are recommended to stop events by jQuery. If return false; does the trick, though, you can keep that.
I haven't used .live yet, but I think that should do the trick. Make sure that you get jQuery 1.3 in your server before trying this, though. :)

Categories

Resources