Closable tab in kendo ui - javascript

I looked carefully through documentation, but could not find something that is so popular and extremely useful in many other libraries - I mean closable tabs. I wish there was something like:
$("#tabstrip").kendoTabStrip({
dataTextField: "Name",
dataContentField: "Content",
dataSource: [
{ Name: "Tab1", Content: "Tab2: content", closable: true } // <-- this is what I want
]
});
But, unfortunatelly. I could not find anything similar to that, but I hope some easy solution (without a lot of funky css and js stuff) exists.

Well here is a quick demo I have knocked up for you.
Closable tabs in Kendo
Essentially I have done two things:
1) Add a span tag with a data attribute indicating the index of the tab
<div id="tabstrip">
<ul>
<li>Tab 1 <span style="border:1px solid red;" data-tab="0">*</span></li>
<li>Tab 2 <span style="border:1px solid red;" data-tab="1">*</span> </li>
</ul>
<div>Content 1</div>
<div>Content 2</div>
</div>
2) Added a click event to the span tags to remove the tab and then re-sequence the tab number.
var tabStrip = $("#tabstrip").kendoTabStrip().data("kendoTabStrip");
$(document).ready(function(){
$("span[data-tab]").on('click',function(e){
//indicate I am removing a tab
console.log("removing tab::");
//find the tab I am removing based on click
var tabIndex = $(this).data("tab");
//show tab index 0 positioned
console.log(tabIndex);
//remove tab.
tabStrip.remove(tabIndex );
//now find any remaining tabs and reindex them.
var reIndex = $("span[data-tab]");
console.log(reIndex);
if(reIndex !== null && reIndex !== undefined && reIndex.length > 0 )
{
var counter = 0;
reIndex.each(function(item){
$(this).data('tab',counter);
counter++;
});
}
});
});
Hopefully this is the sort of thing you are looking for with kendo.

Related

materialize collapsible: how to determine which section is open?

I have a materialize collapsible which works as expected. Something similar to:
<ul class="collapsible">
<li>
<div class="collapsible-header">Title1</div>
<div class="collapsible-body" />
</li>
<li>
<div class="collapsible-header">Title2</div>
<div class="collapsible-body" />
</li>
</ul>
In a later process, when pressing a button I need a javascript function to modify its behavior depending on which section is open.
How can I determine which section is open?
I guess one possibility would be to store in a hidden element the index of the section when it is selected but I don't know how to do it.
Materializecss add an active class to an open collapsible item by itself. So you can use it to understand which collapsible item is open.
You can use this jquery code :
$(document).on("click","ul.collapsible li", function(){
var elem = document.querySelectorAll("ul.collapsible li");
var index = "none"
for (var i = 0; i < elem.length; i++) {
if (elem[i].className == "active") {
index = i;
}
document.getElementById("show").innerHTML = index;
}
})
This code show index of opened collapsible item for you.
Here is complete example : jsFiddle

Hide <h3> when all ul>li of group does not contain filter term

I've created a small script that filters my ul with a nested ul inside of it. The only issue with my script is I want to hide the title of the nested ul if none of the li's contain the search term, but I am not sure how to go about checking the li's of each "group" as opposed to each li individually. The way it stands, it will display the title if it finds an li in the group matching the search term, but it will immediately turn around and hide the title if the same group contains an li that DOES NOT contain the search term. I know what I'm doing wrong, but I am not as skilled in jquery and cannot seem to visualize how to go about this.
Any help would be great. My code is below:
HTML:
<div id="sitemap">
<h3>Hospital Data Solutions Interactive Site Map</h3>
<hr/>
<p id="header"><input type="text" placeholder="Filter Site Map"> - Use this field filter our list of databases: Search by Topic or Topic Subgroup</p>
<ul id="toplist">
<li class="group">
<h3 class="sTitle">Available Beds - <a style="font-size:18px;">Go to Section</a></h3>
<ul class="sublist">
<li>General</li>
<li>ICU</li>
<li>CCU</li>
<li>BICU</li>
<li>SICU</li>
<li>Other</li>
<li>Hospice</li>
<li>Total</li>
</ul>
</li>
<hr/>
<li class="group">
<h3 class="sTitle">Discharges - <a style="font-size:18px;">Go to Section</a></h3>
<ul class="sublist">
<li>Medicare</li>
<li>Medicaid</li>
<li>Other</li>
<li>Total</li>
</ul>
</li>
</ul>
</div>
Jquery:
$(function(){
$('input[type="text"]').keyup(function(){
var searchText = $(this).val().toLowerCase();
$('.sublist>li').each(function(){
var currentLi = $(this).text().toLowerCase();
if(currentLi.search(searchText) != -1){
$(this).slideDown();
$(this).closest('.group').children('.sTitle').show();
} else { $(this).slideUp(); $(this).closest('.group').children('.sTitle').hide();}
});
});
});
First, select the .sublist elements instead of the lis.
Then iterate that collection using .each(), and use .children() to test each li like you currently are, except use .filter() instead of .each(). This will give you a collection as a result. If the collection is empty, there were no matches. If not, then there was a match.
$('input[type="text"]').keyup(function(){
var searchText = $(this).val().toLowerCase();
$('.sublist').each(function(i, sub){
var matches = $(sub).children().filter(function(i, li) {
return $(li).text().toLowerCase().search(searchText) != -1;
});
if (matches.length) {
$(sub).slideDown().prev().show();
} else {
$(sub).slideUp().prev().hide();
}
});
});
Now the slideDown/Up and show/hide are happening once per sublist instead of on every child li. And I just used .prev() to get back to the h3 element.
If you're going to be hiding those list items that don't match your search you're going to want to deal with them individually anyway, so I wouldn't abandon that approach. So you just need a way to check to see if the term was found somewhere in the search of the nested list. Here's what I might do to utilize what you already have.
After you capture the search term, loop through each of the sublists and set a flag to false; this will be where we capture whether there were any matches. Then loop through that sublist's items, and if you find a match set the flag to true, showing or hiding the item as necessary. Then, after you've checked all the items show or hide the heading based on that flag. It might look something like this:
$('.sublist').each(function(){
found = false;
$(this).children("li").each( function() {
var currentLi = $(this).text().toLowerCase();
if(currentLi.search(searchText) != -1){
$(this).slideDown();
found = true;
} else {
$(this).slideUp();
}
});
if(found) {
$(this).closest('.group').children('.sTitle').show();
} else {
$(this).closest('.group').css("list-style-type", "none");
$(this).closest('.group').children('.sTitle').hide();
}
});
I added a css line to show/hide the header's disc to avoid having that hanging there if everything else disappears. Hope this helps! Let me know if you have any questions.

Activate Current Content Part in jQuery UI Accordion Menu

I'm trying to figure out how to dynamically activate the correct content part of a jQuery UI Accordion menu depending on the page currently being viewed. I've searched extensively and it seems like others have had issues with this in the past, but I haven't yet found a solution that works for me. I know that active can be set to open a certain index of the menu, but I need to do this dynamically.
I'm thinking that I can achieve what I want using the activate method, I just can't seem to figure it out. I'd like to stay away from setting cookies as that usually won't work with back/forward buttons and direct navigation via a specific url. Anyone have any ideas? Thanks in advance!
Here is the simplified structure of my menu:
<div id="menu">
<div id="sections">
<div class="grouping accordion">
<a id="heading1" href="#">Heading #1</a>
<div class="sub-items">
Item #1
<br />
Item #2
</div>
</div>
<div class="grouping accordion">
<a id="heading2" href="#">Heading #2</a>
<div class="sub-items">
Item #4
<br />
Item #6
</div>
</div>
</div>
</div>
And here is my jQuery Accordion init:
$('#sections').accordion({
header: '> .accordion > a',
autoHeight: false,
collapsible: true,
active: false,
animated: 'slide'
});
So if you are currently on the /item4 page for example, the group under Heading #2 should be expanded.
EDIT:
I found what seems to be a pretty good solution and posted that as an answer below, hopefully this will help someone with a similar problem!
To activate a specific tab, you'll want to use the accordion('activate', index) method. Example:
$( "#sections" ).accordion('activate', 2);
However, you will need something that defines an index key per page. You can probably even generate this dynamically. I would probably create a Pages object:
Pages = {
"heading1" : {
"id": 1,
"is_active": false,
"items": {
"item1": {
"href": "item1",
"name": "Item #1"
},
"item2": {
"href": "item2",
"name": "Item #2"
}
}
},
"heading2" : {
/* etc*/
},
}
With some hackish jQuery magic, you can loop through your headings
var active_heading_index = null;
$.each(Pages, function(heading) {
$.each(heading.items, function(item) {
if($(location).attr('href') == item.href) {
heading.is_active = true;
// or
active_heading_index = heading.id
}
});
});
if(active_heading_index) $( "#sections" ).accordion('activate', active_heading_index);
Anyhow, I'm sure there are cleaner and more efficient ways of doing it.
While working on some CSS for the active headings on the menu I stumbled on a pretty clean and easy solution. Looks like I might have been overthinking things!
Using the same HTML as in the question, here's the JavaScript that is working for me:
//accordion menu
$('#sections').accordion({
header: '> .accordion > a',
autoHeight: false,
collapsible: true,
active: '.selected',
animated: 'slide'
});
//add currentPage class to current menu item based on url
var url = window.location.href;
url = url.substr(url.lastIndexOf("/") + 1);
$("#sections").find("a[href='" + url + "']").addClass("currentPage");
//get id of header anchor tag
var headerId = $(".currentPage").parents(".accordion").children("a").attr("id");
//check if headerId is set, if so activate that id
if (headerId) {
$('#sections').accordion('option', 'animated', false);
$('#sections').accordion('activate', $('#' + headerId));
$('#sections').accordion('option', 'animated', 'slide');
}
This solution is pretty simple, it gets the current page from the url and compares it against each link in the accordion menu. If it finds a match, it gives that link a class of currentPage (which allows us to then style that link accordingly via css). Then it looks for a parent of that link with a class of .accordion, finds the first child link (the accordion header) and grabs the header's id. Assuming a header id has been found, we can then use the activate method to expand the correct section.
If you are going back to the server for every page click (standard non Ajaxy way), the server can add a "selected" class to the proper node. So you'd get back something like this at the client (I'm only writing the essential code, skipping most of the labels).
<ul id="menu">
<li>
<ul>
<li>
</li>
<li class="selected">
Menu 102
</li>
<ul>
</li>
<li>
...
</li>
<ul>
Then simply find the proper index to give to the activate property of the accordion.
$(document).ready(function() {
var index = $("li.selected").parents("li").last().index();
$("#menu").accordion({
active: index,
collapsible: true
});
});
The parents("li").last() jQuery returns the top most element. This only works if you only have one sub element with the class "selected", which should be the case for your menu.
I did it using this code:
var newsNum = parseInt(window.location.hash.slice(1));
$(document).ready(function(){
$("#menu").accordion('activate', newsNum );
});
And the url looks like example.com/index.html#1

jquery sortable: sorted item triggers reordering

I have a list of items that represent div layers. When I sort one of these list items, I want their respective div layers to be sorted aswell.
list: these items are sortable
<ul id="sortable">
<li id="1">Div 1</li>
<li id="2">Div 2</li>
<li id="3">Div 3</li>
</ul>
div layers: these divs will be reordered
<div id="div_container">
<div id="div1">Div 1 item</div>
<div id="div2">Div 2 item</div>
<div id="div3">Div 3 item</div>
</div>
example: when li#1 moves to the second place, then div#1 goes to the second position automatically
init
$('#sortable').sortable();
This code could be what you want if I got what you are asking for:
http://jsfiddle.net/NsawH/84/
var indexBefore = -1;
function getIndex(itm, list) {
var i;
for (i = 0; i < list.length; i++) {
if (itm[0] === list[i]) break;
}
return i >= list.length ? -1 : i;
}
$('#sortable').sortable({
start: function(event, ui) {
indexBefore = getIndex(ui.item, $('#sortable li'));
},
stop: function(event, ui) {
var indexAfter = getIndex(ui.item,$("#sortable li"));
if (indexBefore==indexAfter) return;
if (indexBefore<indexAfter) {
$($("#div_container div")[indexBefore]).insertAfter(
$($("#div_container div")[indexAfter]));
}
else {
$($("#div_container div")[indexBefore]).insertBefore(
$($("#div_container div")[indexAfter]));
}
}
});
This code is portable since it does not use element ID's, however you should parametrize the sortable selector to be able to use them on any two lists eg. if you are binding to the sortable after init.
The code is jQuery dom modification friendly since it uses selector indexes and not node dom indexes. You will see on JSFiddle that i made the div_container a sortable , and it syncs back to the list.
Bind the change event of the sortable (if you want real-time updates) or stop (to just read off the end state), and manually reorder the divs accordingly.

detecting the last list item in jquery/javascript

I have a set of tab (main-tabs) on a website and each tab has another set of tabs (sub-tabs).
I want to use arrow keys on a keyboard to navigate the tabs, instead of a mouse.
These tabs are just HTML list items <li>
When I reach the last sub-tab with the arrow key, I want it to go back to the next main tab so it can display its own sub-tabs, and carry on the navigation inside it.
My question is, how can I detect, in jQuery/javascript, when I've reached the last list item (tab) using the arrow keys i.e. the right arrow key?
Many Thanks
You might be able to use either the :last or :last-child selectors in jQuery. Depending on how your <li> tags are nested, you might also have to use the children() function along with it.
For example, let's say you have the following markup:
<ul id="nav">
<li>List item</li>
<li>List item with sub items
<ul>
<li>Sub list item</li>
</ul>
</li>
</ul>
This would select the last top-level <li>
$('ul#nav > li:last').css('border', '1px solid red');
This would select the last <li> traversing the DOM downward. In this case it's the <li> with text "Sub list item"
$('ul#nav li:last').css('border', '1px solid red');
This would select any <li> tags that are the last child of their parent
$('ul#nav li:last-child').css('border', '1px solid red');
var maintabs = $('.maintab'),
active_maintab_eq = 0,
active_subtab_number = 1;
$(document).keyup( function(e){
if (e.which == 39) {
// right arrow key pressed
if ( active_subtab_number == maintabs.eq(active_maintab_eq).find('li').length ) {
// go to next main-tab
// and reset active sub-tab counter
++active_maintab_eq;
active_subtab_number = 1;
} else {
++active_subtab_number;
}
}
});
Some thing like this, I guess.
You can use .length to find out if a jQuery selector found anything:
var nextSubTab = $(currentSubTab).next("li");
if (nextSubTab.length == 0) {
// oops, end of this tab, switch to next tab
}

Categories

Resources