JQuery not acting as it should - javascript

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

Related

What causes jQuery objects to be different?

Why doesn't the first attempt to close the dialog work? Or maybe a better question is why is jQuery object $("#dialog") different than $(this).parent('div.dialog')?
$('#click').click(function() {
$("#dialog").dialog("open");
});
$("#dialog").dialog({autoOpen:false}).find('li').click(function(){
$(this).parent('div.dialog').dialog('close');
$("#dialog").dialog("close");
});
<div id="dialog">
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
</div>
$(this).parent('div.dialog') will only look up one level to see if the parent matches that selector. It will not traverse any further. The result is an empty set, and as a result using .dialog() has no effect.
What would work here would be closest jQuery API.
$(this).closest('div.dialog')
This would be the same as $("#dialog") in your example.

Backbone.js – changes to li element don't display immediately

What I have in my template is just a bunch of divs and a list, consisting of multiple li elements. The use case is simple, the li elements are a dropdown and are displayed only on clicking a button. When the dropdown is visible and someone begins to type, the matching li element should be selected, or there should be a visual indication.
My approach is this, on a keyup event, I look for the typed word (this is quite easy) in the li elements. I find a few elements, which I've confirmed. Now, when I try to do something with these elements, nothing seems to happen WHILE the dropdown is open (right now, I'm trying to .toggle()) these elements. Now, when I click the button again (which showed the dropdown in the first place) (this click hides the dropdown), and then click the same button again to reveal the dropdown, voila! The values have been changed as they should be – the matching elements have been hidden/shown.
This has me stumped. For company policies, I can't upload the code up here, but I'll be very thankful if someone else has had this problem before and can help me out.
EDIT:
Code: function to change the dropdown on keypress, this is being fired correctly:
filterOptionsForKeypress: function (event) {
var typedString = this.$('input.filter-button-text').val(),
searchToken = _.trim(typedString.toLowerCase().replace(/ /g, '_')),
matchingLi = this.$("li[data-field^='" + searchToken + "']", this.$el), // makes no difference with or without the context, this.$el
that = this;
if (matchingLi && matchingLi.length) {
this.$(matchingLi[0]).html('kaka'); // this change shows only if the dropdown is hidden + shown again
console.log('trying to move focus', this.$(matchingLi[0]).attr('data-field'));
}
// this.$el.append('Some text'); -- this works, I see the changes as they happen
}
And the template looks something like this:
<div class="filter-button filter-option {{if !model.include}}button-red{{else}}button-green{{/if}} toggle-dropdown" data-dropdown-class="{{if !model.include}}button-red{{else}}button-green{{/if}}">
<div class="filter-button-text">${model.option}</div>
<div class="filter-drop"></div>
<div class="dropdown filter-dropdown">
<ul>
{{each model.config.options}}
<li data-field="${$value.op}" data-include='${$value.include}'>${$value.name}</li>
{{/each}}
</ul>
</div>
</div>
EDIT #2:
When the dropdown is open, this is how the html looks:
OPEN:
CLOSED:
So basically, apart from adding a few styles to the enclosing div and a class 'open', I don't see any differences.
The problem was that we're using a plugin for dropdown menus. So basically, what we saw on the screen wasn't what we found selecting with this.$(). The solution? Look globally and with a :visible filter voila, problem solved.

How to deal with the .next() function with hidden elements

I am making a custom drop down menu with arrow key functions as well as being filtered by :contains.
I can't seem to get past the following code. What is happening is that I need to start the selection at the current hovered li, then proceed to the next or previous li that has the class match.
My following code starts correctly but even though it has .next('.match') it wont pass the <li>'s that either don't have the class (match) or are (hidden)
Does the next() function break on hidden elements?
Jquery Code
$('.dropdown_shell.opened li.match.hovered')
.next('.match')
.addClass('hovered')
.siblings()
.removeClass('hovered');
Html
<ul class="scroll">
<li class="selected default match">None</li>
<li class="" style="display: none;">For Sale</li>
<li class="match">For Rent</li>
<li class="" style="display: none;">For Lease</li>
<li class="match hovered">Sale or Lease</li>
<li class="match">New Listing</li>
<li class="match">Open House</li>
</ul>
Your next() function is not doing what you think it is. It looks at the next element, and only matches it if it makes the given selector. Otherwise it returns an empty jQuery object.
Instead, you want nextAll(), which looks at all future siblings, then use the first() method (or :first) selector to match the first one.
You can see this working here; http://jsfiddle.net/DH3hG/
To answer your question about whether next() considers hidden elements; yes it does. Anything that is inserted into the DOM is considered.

Remove inline css of an HTML elements

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.

Why $('a.current').parent('li').addClass('current'); is not working?

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. :)

Categories