Why $('a.current').parent('li').addClass('current'); and $(this).hasClass('current').parent('li').addClass('current'); are not working?
a click event must add li.current
http://jsfiddle.net/laukstein/ytnw9/
Update: Dropbox is Down, so I updated
http://jsfiddle.net/laukstein/ytnw9/1/
with full JS
$(function(){
var list=$('#list'),
elementsPerRow=-1,
loop=true,
// find first image y-offset to find the number of images per row
topOffset=list.find('a:eq(0)').offset().top,
numTabs=list.find('li').length-1,
current,newCurrent;
function changeTab(diff){
// a.current set by jQuery Tools tab plugin
current=list.find('a.current').parent('li').addClass('current').index();
newCurrent=(loop)?(current+diff+numTabs+1)%(numTabs+1):current+diff;
if(loop){
if(newCurrent>numTabs){newCurrent=0;}
if(newCurrent<0){newCurrent=numTabs;}
}else{
if(newCurrent>numTabs){newCurrent=numTabs;}
if(newCurrent<0){newCurrent=0;}
}
// don't trigger change if tab hasn't changed (for non-looping mode)
if (current!=newCurrent){
list.find('li').eq(current).removeClass('current');
list.find('li').eq(newCurrent).addClass('current').find('a').trigger('click'); // trigger click on tab
}
}
list
// set up tabs
.tabs("#content",{effect:'ajax',history:true})
// find number of images on first row
.find('a').each(function(i){
// $(this).hasClass('current').parent('li').addClass('current');
if(elementsPerRow<0&&$(this).offset().top>topOffset){
elementsPerRow=i;
}
});
// Set up arrow keys
// Set to document for demo, probably better to use #list in the final version.
$(document).bind('keyup focus',function(e){
var key=e.keyCode;
if(key>36&&key<41){
if(key==37){changeTab(-1);} // Left
if(key==38){changeTab(-elementsPerRow);} // Up
if(key==39){changeTab(+1);} // Right
if(key==40){changeTab(+elementsPerRow);} // Down
e.preventDefault();
}
});
// toggle looping through tabs
$(':button').click(function(){
loop=!loop;
$('#loopStatus').text(loop);
});
$('a.current').parent('li').addClass('current');
});
EDIT: Adding HTML from jsFiddle link that was omitted from question
<button>Loop</button> <span id="loopStatus">true</span><br />
<ul id="list">
<li><a class="current" href="http://dl.dropbox.com/u/6594481/tabs/one.html" title="one">1</a></li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
<div id="content" style="clear:both;">Loading...</div>
.parent() will only return the element's immediate parent.
If the element is not directly within an <li> element, .parent('li') will return an empty set.
You probably need to call .closest('li').
EDIT: The <li> is the direct parent; that's not your issue.
The hasClass function returns a boolean. Your second line is wrong; you need to call .filter.
$(this).hasClass('current').parent('li').addClass('current'); certainly won't work, because hasClass returns a boolean value (true/false) not the jQuery object. You can't continue chaining after you have called it.
You can use filter instead:
$(this).filter('.current').parent('li').addClass('current');
You only seem to be using that bit of code in the changeTab function.
This only seems to be called when using the cursor keys.
If I go to your demo and use cursor keys the orange highlight moves around. If I click it doesn't but there isn't any code that picks up clicks that I can see...
Edit to add: (converted from comment and realised it was actually an extension to my answer)
After looking at the tabs code that you pointed me at I'm still not sure it is calling the code in the changeTab function.
If I change the tabs declaration to
.tabs("#content",{effect:'ajax',history:true, onClick:function(){changeTab(0)}})
then it will highlight the clicked cell but of course won't deselect the old one because the current index has already changed.
I've put a crude fix in for that that can be seen at jsfiddle.net/bhvYM (a fork). That involves clearing all li.current classes before setting the new one. Its a bit hacked so may not be doing everything exactly as you want (I didn't look closely at the current/newCurrent code) but hopefully its a start that will help you get it working to where you want.
My thought is that this now at least puts the li class on which I think is the thrust of your question. If it is not then I have totally missed the point here. :)
Related
what I want to achieve is setting all occurences of a class to their designated data - except the particular occurence clicked, which is to be set to something unique. My code below gives an undefined error on the "y" variable. How would I go about contextualizing the dataset?
<div id="menu">
<ul>
<li id="menu-tos" data-info="TERMS OF SERVICE">TERMS OF SERVICE</li>
<li id="menu-contact" data-info="CONTACT">CONTACT</li>
<li id="menu-signup" data-info="SIGN UP">SIGN UP</li>
<li id="menu-login" data-info="LOG IN">LOGIN</li>
</ul>
</div>
<script>
$('#menu ul li').click(function() {
i = $(this.id);
y = dataset.info;
$('#menu ul li').not(i).html(y);
$(i).html('Something unique');
});
</script>
(to skip the explanation and see a working version, scroll to the bottom)
Your undefined error is because you trying to access dataset as if it is a variable, when it is actually a property of DOM element objects (details here).
Also, if I'm understanding your desired functionality correctly, there are a couple other issues you'll run into with your code:
i = $(this.id); this will resolve to $('menu-tos'). To select via ID, you'd need a #, like this: $('#menu-tos'). In your case, though, there's really no reason to set the current element to a variable anyway, because it is already available via $(this).
As mentioned above, y = dataset.info; won't work because dataset is a property on HTML Element objects, not a variable. Since you're using jQuery, it'd be easier to use $(this).data('info').
$('#menu ul li').not(i).html(y); this will not do what you said you're trying to do. This will set the HTML of all other <li> elements to the value of the one you just clicked. To set each one to its own value, you'll need to loop through them using .each()
$(i).html('Something unique'); assuming i was set correctly as a jQuery object, you don't need the jQuery wrapper here, you can just use i.html('Something unique');
A couple other things that would help your code:
The way you are setting your variables now (without using var), it will set them on the global scope. This may work, but it can cause collisions, and is generally avoided. Use var like var i = $(this);, and it will keep that variable only within the scope of your click() function.
When using jQuery, you should wrap your code in a $(document).ready() callback. This will ensure that the DOM is loaded before jQuery tries to bind any event handlers (such as your click handler).
After fixing the issues mentioned here, the javascript code ends up looking like:
$(document).ready(function() { // ensure document is loaded before running code
$('#menu ul li').click(function() {
// set all other elements to their own data-info attribute value
$('#menu ul li').not(this).each(function() {
var info = $(this).data('info');
$(this).html(info);
});
// set the clicked item to 'Something unique'
$(this).html('Something unique');
});
});
Checkout the working code on this JSFiddle.
Try like this:
$('#menu ul li').click(function() {
$(this).siblings().each(function() {
var info = $(this).data('info');
$(this).html(info);
});
$(this).html('Something unique');
});
Full example here https://jsfiddle.net/_jakob/q49kq3c5/1/
I am trying to make a "drop down" menu where you click a div and the sibling below it will become visible or disappear. It should be extremely simple, but it is giving me trouble for some reason.
$(".dropDownClick").click(function(){
alert($(self));
$(self).next().css("display",(node.css("display")=="inline")?"none":"inline");
});
This code returns [object Object] and then doesn't change the display css of the next sibling. After a bit of testing I found that $(self).next(); will actually break the code (if I try to do something like alert($(self).next()); the code will not execute). I am assuming this is because there is no next sibling? But my HTML would suggest otherwise:
<div class="dropDownClick"><h1>Drop</h1></div>
<div class="dropDown" style="display: none;">
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
Shouldn't the div with the class "dropDown" be selected when I call .next()?
it should be this not self, also you can use .toggle() instead of manually applying the display value
$(".dropDownClick").click(function () {
$(this).next().toggle();
});
this is a special variable, which is always available - but self/node are custom variables which has to be declared before using else it will throw a reference error
Demo: Fiddle
I'm using wordpress 3.5 and create menu with submenus. It's structured like this:
<ul class="menu">
<li id="menu1">Menu 1</li>
<li id="menu2">Menu 2</li>
<li id="menu3" style="z-index:100;">
Menu 3
<ul class="submenu">
<li id="submenu1">submenu1</li>
<li id="submenu2">submenu2</li>
<li id="submenu3">submenu3</li>
</ul>
</li>
</ul>
The problem is the menu with submenus, it's automatically attached a z-index with value 100. I don't want it to be like that because it gives me trouble on adding lavalamp effect to those menus.
I tried to edit the z-index by using jquery just after the menu is created using wp_nav_menus simply like this:
jQuery(document).ready(function(){
jQuery("#menu3").css("z-index", "0");
});
But unfortunately, it doesn't work. How can I remove that inline css style?
Use the removeAttribute method, if you want to delete all the inline style you added manually with javascript.
element.removeAttribute("style")
Reset z-index to initial value
You could simply reset the z-index to it's initial value causing it to behave just like the li would without the style declaration:
$(function(){
$('#menu3').css('z-index', 'auto');
});
You can go vanilla and use plain javascript (code should run after your menu html has loaded):
// If you're going for just one item
document.querySelector('#menu3').style.zIndex = 'auto';
Remove style attr
You could use jQuery to remove the style attributes from all your list:
Note: Keep in mind this will remove all styles that have been set to your element using the style attribute.
$(function(){
$('#menu3').removeAttr('style');
});
Or vanilla:
// Vanilla
document.querySelector('#menu3').style = '';
If you want remove all inline styles, Pranay's answer is correct:
$("#elementid").removeAttr("style")
If you want to remove just one style property, say z-index, then you set it to an empty value:
$("#elementid").css("zIndex","")
From the jQuery documentation (http://api.jquery.com/css/):
Setting the value of a style property to an empty string — e.g. $('#mydiv').css('color', '') — removes that property from an element if it has already been directly applied, whether in the HTML style attribute, through jQuery's .css() method, or through direct DOM manipulation of the style property.
This is what I consider a better approach because it only removes the z-index style instead of the whole style attribute. Here is a working Fiddle.
//As commented by #DA this is enough
$("#elementid").css("zIndex","")
//this could be useful in another situation so I will leave it :)
$(document).ready(function () {
$('#menu3').attr('style', function(i, style){
return style.replace(/\z-index\b[^;]+;?/g, '');
});
});
Hope it helps.
I made a table out of a simple list structure:
<html>
<body>
<ul id="Column:0">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
<ul id="Column:1">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
<ul id="Column:2">
<li id="Row:0></li>
<li id="Row:1></li>
<li id="Row:2></li>
<li id="Row:3></li>
<li id="Row:4></li>
</ul>
</body>
</html>
Now I want to add a simple .mouseover() to every row, for e.g. changing the color of a row, when hovered. And this is what I figured out, so far:
for (var i = 2; i <= _totalRows; i++) {
var row = $('#TimeTable ul li:nth-child(' + i + ')')
row.each(function() {
$(this).click(function(evt) {
var $target = $(evt.target);
console.log($target.nodeName)
if (evt.target.nodeName == 'DIV') {
console.log(evt.parent('li'));
}
}); //end $(this).click(fn)
}); // end each(fn)
}
I get a set of all <li> objects matching to :nth-child(i) where i is the rows number.
var row = $('#TimeTable ul li:nth-child(' + i + ')')
Now I just iter this set through to add a .click(fn) to every <li>.
This works fine. Every cell has it's .click(fn) attached to it.
But the following, what to do on a click, is where I'm stuck for several hours now:
var $target = $(evt.target);
console.log($target.nodeName)
if (evt.target.nodeName == 'DIV') {
console.log(evt.parent('li'));
}
I simply don't get it to run.
You can actually ignore this gibberish, as it's just the last of several things I already tried here.
What I'm trying to do is simply select every <li> with an id='Row:X' and manipulate its CSS. The best I yet had was, that I can click a cell, but no matter in what row this cell is, the last one gets colored. I remember having used i as the row-index, when that happened, so I might miss some understanding of event-handling here, too.
Use a class name for duplicate groups of elements not an ID. If you give row one a class of "Row1" the selector is simply:
$('.Row1')
Then:
$('#TimeTable li').removeClass('highlight');
$('.Row1').addClass('highlight');
If you just wish to change the color on mouseover:
$('#TimeTable ul li').mouseover(function(){
$(this).css('background','red');
});
$('#TimeTable ul li').mouseout(function(){
$(this).css('background','green');
});
Make your ID's like so: C1R1 (Column1Row1) and so on
JQuery read/google up "jquery each"
JQuery read/google up "jquery bind click"
JQuery read/google up "jquery attr" and "JQuery val()"
This will give you the knowledge to write your own and most importantly understand it better. You will want to achieve the following (your close but no for loop required):
A list which JQuery attaches a click event handler to each LI, and then when the click happens the ID can be retrieved.
PS. There's a time and place for tables, they 9/10 times nearly always better for displaying data than CSS is. If you have a complex multi column row and want fiexed hights and no JS to fix things or do anything smart you can have a table and css :Hover on TR for stying mouse over and out etc. Heights are also constant.
PS. PS. If your data is dynamic and coming from a database and the whole row is an ID from the database I tend to avoid using the html ID attribute for this and make my own. You can retrieve this via attr("myattribute");
NOTE ON CSS and IDS:
Standard practice for ID's are to be used once on a page.
Class for repeatable content
Good luck.
I have following HTML
<div id="finalTree">
<ul>
<li class="last" style="display: list-item;">
<a id="DataSheets" href="#">Data Sheets</a>
</li></u>...........</div>
and I am first hiding all these li and then trying to show those li which match to selector. Here is my JavaScript. Here filterData is id of links.
function filterLeftNavTree(filterData){
jQuery("ul.treeview").find("li").hide();
var selectors =[];
if(filterData.indexOf("|")!=-1){
var filterData = filterData.split("|");
for(i=0;i<filterData.length;i++){
selectors.push('#'+filterData[i]);
}
var filtered = selectors.join(',');
$(filtered ).show();
}else{
$('#'+filterData+).show();
} }
the last two line doesn't works...
any one can tell me what can be possible reason. Actually I tried to show li with :has, :contains, find().filter() but all these are taking too much time if I have large tree.
Do I am trying to show it by using multiple selector, but it's not showing any thing. Any alternative having faster way to show it will be highly appreciated.
What you have (aside from the syntax error #verrerby mentioned) should be working, but why not cut down on that code a bit?
You can slim things down by adding the # on every element after the first as part of the .join(), this also greatly simplifies the logic. You can reduce it down to:
function filterLeftNavTree(filterData) {
$("ul.treeview li").hide();
$('#'+filterData.split('|').join(',#')).show();
}
Also note the change removing .find(), it's faster in browser that support it to use a single selector, and just as fast in all the others.
The only other possible reason I see for your code not working is jQuery is used for the hide and $ is used on the show, is it possible $ refers to something else? (e.g. ptototype?) To test just replace $ with jQuery on the .show() call.
You have an extra +' in the last statement, and you could do it in multiple statements instead of one (the #{id} selector is very fast):
if(filterData.indexOf("|")!=-1){
var filterData = filterData.split("|");
for(i=0;i<filterData.length;i++){
$('#'+filterData[i]).show();
}
}else{
$('#'+filterData).show();
}