jQuery doesn't recognise that the class changed, although the Browser does - javascript

I have been trying out to create a Dropdown-menu with jQuery. I have 3 Sub-folders with 3 sub-sub-folders each (correct me if this is the wrong term). Depending on wether the Sub-folder is collapsed (Sub-subs invisible) or expanded (Sub-subs visible) there´s a little arrow pointing downwards when expanded and to the right when collapsed. I´m a Newbie and don´t want to use many external scripts, so I remove the Subshown_arrow Class and add the Subhidden_arrow Class when clicked (or the other way).
<img id="arrow" class="Subshown_arrow" /> Sub-forum 1
<li class="sub-sub"> <a href="#"> Sub-sub-forum 1 <li>
<li class="sub-sub"> <a href="#"> Sub-sub-forum 2 <li>
<li class="sub-sub"> <a href="#"> Sub-sub-forum 3 <li>
I removed the scr here ^, normally it´s there.
var main = function() {
$(".Subshown_arrow").click(function() {
alert("Subshown_arrow clicked!");
$(this).removeClass("Subshown_arrow").addClass("Subhidden_arrow");
});
$(".Subhidden_arrow").click(function() {
alert("Subhidden_arrow clicked!");
$(this).removeClass("Subhidden_arrow").addClass("Subshown_arrow");
});
};
$(document).ready(main);
However, when I click the Arrow for the first time, it rotates as expected. But when I click it another time, jQuery reacts as if it was clicked for the first time. The alerts print out "Subshown_arrow clicked!" every time.
But when I tried it out in the Browser and used Chrome´s built-in tools to view the Code, the Class changed. That means that changing the Class works, but my jQuery script ignores it.
What have i done wrong? Or is there a better way to do it?

Your problem has already been solved thousands of times, you are binding to .Subhidden_arrow and .Subshown_arrow classes when the first doesn't exist yet. You need to bind the events differently:
$('body').on('click', '.Subhidden_arrow', function ( e ) {});
This will work also on dynamically created (changed) elements.

If you use .on it will work when classes changes as new handler will be assigned to it. but when you use .click it is assigend to the object that had the matching class at first and although the class has changed but still the old handler is assigned to it.
var main = function() {
$("body").on("click",".Subshown_arrow",function() {
alert("Subshown_arrow clicked!");
$(this).removeClass("Subshown_arrow").addClass("Subhidden_arrow");
});
$("body").on("click","Subhidden_arrow",function() {
alert("Subhidden_arrow clicked!");
$(this).removeClass("Subhidden_arrow").addClass("Subshown_arrow");
});
};

You are using an img without any src and if you have more images then i would mention to not to use same ids.
So, what you can do is give a common class name to the element:
<img class="arrow Subshown_arrow" />
<!----------^^^^^-------like this one---->
Now you can use the class arrow to bind the click event and you can use toggleClass() method to change the classes:
$(".arrow").click(function() {
$(this).toggleClass("Subshown_arrow Subhidden_arrow");
});

As mentioned the problem is that the click is bound on document load, at which time there are no elements with a class subhidden_arrow. This can indeed be solved by using a parent elements click and a filter on the class using (on). However, the original bound click event can also be reused to toggle the classes:
$(".Subshown_arrow").click(function() {
$(this).toggleClass("Subshown_arrow").toggleClass("Subhidden_arrow");
});
The click is bound to the element on load and reacts on both 'states', regardless of which class it holds then.
An example Fiddle with a slight alteration to make the containing anchor react to the click event.

Better way
var main = function() {
$("#arrow").click(function() {
$(this).toggleClass("Subshown_arrow").toggleClass("Subhidden_arrow");
});
};
$(document).ready(main);

Related

toggleClass() only toggling to one class

I'm having trouble with a jQuery/Angular function being executed on click.
<a ng-click="like()" href="#" class="like like--yes"></a>
Basically, when a click occurs on a like button, I want to toggle the like--yes and the like--no classes. I've inspected the DOM while clicking, and once it has been set to like--no, it refuses to change back.
$scope.like = function() {
$('.like--no').toggleClass('like--no like--yes');
$('.like--yes').toggleClass('like--yes like--no');
}
I need two different functions so to speak, as I'm adding different animations depending on whether it's a like/unlike.
Any idea where I'm going wrong? There's more to it, but I've stripped some of the unnecessary code out for clarity.
Thanks.
I see that you are using AngularJS so instead of using jQuery, why not use ngClass?
Like this:
<a ng-click="toggleLike()" ng-class="{'like--yes': like, 'like--no': !like}">Hello World!</a>
Plunkr
It seems there is a logical issue
$scope.like = function() {
$('.like--no').toggleClass('like--no like--yes');
$('.like--yes').toggleClass('like--yes like--no');
}
Case:- first line changes like--no to like--yes and after that second line changes like--yes to like-- no again.
You should try .hasClass() function to check whether element has class then use toggle.
It seems like the second line is overwritting the first one.
It sets the class to like--yes and the second line catches the like--yes and set it to like--no everytime.
Try something like:
$scope.like = function() {
if( $('.like').hasClass( 'like--yes' ) ) {
$('.like').removeClass( 'like--yes' );
$('.like').addClass( 'like--no' );
} else {
$('.like').removeClass('like--no');
$('.like').addClass('like--yes');
}
}
Maybe you need change $('.link') to $(this) to get the actually clicked element.
It's generally frown upon to deal with DOM jQuery-style inside an Angular's controller, which is what you attempted to do and the other answers suggested.
Just have a variable that reflects the like state (you can set it directly in the View or inside the $scope.like() function and use ng-class to toggle the class:
<a ng-click="like=!like" href="#" ng-class="like ? 'like--yes':'like--no'"></a>
try this
$('.like').on('click',function(e){
e.preventDefault();
$(this).toggleClass('like--no like--yes');
if($(this).text() == 'like'){
$(this).text('unlike');
}else{
$(this).text('like');
}
});
and html
like
JSFIDDLE

Jquery click function exclude children

Hey I'm having an issue figuring this one out.
JS
$('.jrm-menu-categories,#overlay-2').click(function() {
$('#overlay-2').toggle();
$('#overlay-3').hide();
});
HTML
<ul id="megaUber" class="megaMenu">
<li id="menu-item-1459" class="jrm-menu-categories">
<ul class="sub-menu sub-menu-1">
So basically what my JS does is create an overlay/modal effect when a sub menu is opened via click. I have the code repeated a few times with different classes and overlay ids hence the last line of code (needed so that only one overlay is shown at a time). Quickest and simplest way for a beginner like me, but that's not the subject.
When a sub-menu is open, and a user clicks anywhere in the sub-menu it toggles the overlay. I'm assuming this is because when I selected .jrm-menu-categories in the JS, it also selected the child elements, which happen to be .sub-menu
I'm thinking I need to use the .not() function, but can't figure it out.
can you guys help me with this? if possible write the code so I can try it out
Thanks!
You can try adding a second click handler to the children that will always return false. That way the click won't propagate up and dismiss:
$('.jrm-menu-categories').children('.sub-menu').click(function (e) {
e.stopPropagation(); // prevent click propagation, so parent click never fires.
})
You can test for the clicked item.
$('.jrm-menu-categories,#overlay-2').click(function(e) {
if (this == e.target){
$('#overlay-2').toggle();
$('#overlay-3').hide();
}
});

Error when trying to execute two onclick actions on the same div

I have a little problem here, and if someone could help me, I will truly appreciate.
I have a menu that opens when I click on a div, and once open, I want to close the menu clicking again on te same div. The problem is that I can open the menu but I can't close it.
Here is my code:
<script>
$(document).ready(function () {
$("#menuResp").click(function () {
$('#profile_menu').css('margin-left','0px');
$('#menuResp').css('margin-left','315px');
$('#menuResp').attr('id', 'menuResp2')
});
$("#menuResp2").click(function () {
$('#profile_menu').css('margin-left','-300px');
$('#menuResp2').css('margin-left','0px');
$('#menuResp2').attr('id', 'menuResp')
});
});
</script>
<div id="menuResp">
<ul id="menuRespCss">
<li class="icon-css">
<a>Menu</a>
</li>
</ul>
</div>
Anyone have an idea of why this doesn't work?
What your code is doing is setting callbacks at the moment, when the initial DOM is being built. Of course, there is no #menuResp2 yet. Insdead, set the callback on the document element (or body, or some other parent element), specifying the selector of your menu - this element will fire the event. This will work:
$(document).ready(function () {
$(document).on('click', "#menuResp", function () {
$('#profile_menu').css('margin-left','0px');
$('#menuResp').css('margin-left','315px');
$('#menuResp').attr('id', 'menuResp2')
}).on('click', "#menuResp2", function () {
$('#profile_menu').css('margin-left','-300px');
$('#menuResp2').css('margin-left','0px');
$('#menuResp2').attr('id', 'menuResp')
});
});
But. I would stroungly recommend not to change the ID attribute, but to work with classes instead.
you need to add the click handler like this
$(document).on('click', '#menuResp', function(){
$('#profile_menu').css('margin-left','0px');
$('#menuResp').css('margin-left','315px');
$('#menuResp').attr('id', 'menuResp2');
});
.click() only works for elements that are already created, using .on() will cover elements that will be created later.
you should really be identifying the element by class though , and using .addClass() and .removeClass() like the comment suggest
just use toggle. if the item is closed, it will open, if its open, it will close. all the answers above do not check to see if the item is open already or not.
$(document).on("click", function(e){
e.preventDefault();
$('#menuResp').toggle();
$("##menuResp2").toggle();
})
easier would be to give element a single class and just toggle once on class name, rather than changing the ID of the item, this second item would not have an avent binding added to it. But at the same time. You dont need the ID when you can just toggle with class. like so:
$(".clasname").toggle();
this will open any element that is closed with the class of clasname. this will also, at the same time, close all elements that have that class name, and are also open

How to perform: onClick Javascript, hide a div with transition effect

This is a question that is related to a previous question of another member which can be found here.
This is the Javascript function to hide a div (which is an answer to the other member's question):
function hide(obj) {
var el = document.getElementById(obj);
el.style.display = 'none';
}
The HTML is:
<div id='hideme'>
Warning: These are new products
<a href='#' class='close_notification' title='Click to Close'>
<img src="images/close_icon.gif" width="6" height="6" alt="Close" onClick="hide('hideme')" />
</a>
</div>
My followup question to this is: how can I add a cool effect of transition? The result will be the div 'hideme' would close slowly. Is there a work around for this?
Thanks so much everyone! It would be highly appreciated!
Note: I'm a noob with Javascript. 0-0
$("#"+el).fadeOut(500);//el must be the id of the element
If you're using jQuery
function hide() {
$(this).parent().fadeOut();
}
As this is triggered by an event the 'this' variable will be set to the element from which it came, as you want the parent element to vanish when it's clicked this will do the trick
EDIT: For this to work you may have to play with your HTML and how many $(this).parent().parent()... you need but this would be the best way to go about it, then you don't need to pass the ID around
EDIT 2: So .parent() selects the element containing the selected element, so in this case $(this) refers to the button that was clicked as that's where the click event came from.
So $(this).parent() refers to the container element, in this case the a element and therefore the $(this).parent().parent() refers to the div element which you want to hide.
So you could give the image a class of 'closable' then do the following
$('.closable').click(function() {
$(this).parent().parent().fadeOut();
}
This means whenever you click something with the class closable it will go up the DOM tree two elements to (with .parent().parent()) and then fade it out.
This will allow you to remove the on click event from the image, you just need to put the handler above in the jQuery document.ready function which looks like:
$(document).ready(function() {
//Click function here
});
A popular choice for this would be JQuery UI's effect method.
With this, you can write some very simple Javascript to hide your div in a stylish manner, for example:
function hide(obj) {
$(obj).effect("scale");
}
EDIT:
Here's an example jsFiddle
Use jQuery to do transition effects:
$(function(){
$("a.close_notification").click(function(e){
e.preventDefault();
// stop other animations and hide, 500 milliseconds
// you can use the function fadeOut for that too
$("#hideme").stop().hide(500);
});
});

How to tell JavaScript to do nothing?

I have a small chunk of code, like this:
$("div.footerMenu li").click(
function () {
$("div.onScreen").hide();
$(this).children("div.onScreen").fadeIn('fast');
},function(){
$("div.onScreen").hide();
});//click
And when I click on <li> the div .onScreen shows nicely, but when i click on this div, that just showed up the functions is hiding in and showing again, but I don't want it to execute this function again. So my question is: How can I somehow "detach/exclude/hide" this div from Javascript?
update:
The thing is that with this method and with others with .one() the rest of menu is not working. There is the site with the problem here . I want this div that shows up stay there, when I click on it, but when I click on their items <li> I want to other div's (submenus) to show up (warning - big images on that site).
The html looks like this:
<div class="footerMenu"> <ul> <li>HOME<div class="onScreen"><div style="padding:50px;"><img src="fillTxt.png"></div></div></li> <li>PLENER<div class="onScreen"> <div style="padding:50px;"><img src="fillTxt2.png"></div></div> </li> <li>STUDIO<div class="onScreen"> <div style="padding:50px;"><img src="fillTxt.png"></div></div> </li> <li>INNE<div class="onScreen"> <div style="padding:50px;"><img src="fillTxt2.png"></div></div> </li> </ul> </div>
The simple solution is:
$('div.footerMenu li').unbind('click');
But should you have multiple click handlers on the selector, you may want to only remove one at a time. The way to do that is to store a reference to the function being passed:
function hideItem()
{
...code...
//unbind the click event
$(this).unbind('click', hideItem);
}
$('div.footerMenu li').click(hideItem);
If you want to handle an event only once, you can use the one() method:
$("div.footerMenu li").one("click", function() {
$("div.onScreen").hide();
$(this).children("div.onScreen").fadeIn("fast");
});
You can use .one():
$("div.footerMenu li").one('click', function(){
things_to_happen_only_once();
// unbinding happens automatically
});

Categories

Resources