How to use .not() Jquery Selector on triple selector class? - javascript

I have an issue with two buttons that share common html classes. Both buttons are part of a tutorial. As the tutorial goes through the steps the Skip button appears first. as the tutorial gets to the last step before moving on to anew tutorial page, the 3rd party JS package dynamically adds another class to the skip button and changes the inner html to Continue. My issue is below
One button is:
<a class="introjs-button introjs-skipbutton" role="button" tabindex="0">Skip</a>
The other button is
<a class="introjs-button introjs-skipbutton introjs-donebutton" role="button" tabindex="0">Continue</a>
These buttons are part of a tutorial guide with certain steps. They are not displayed at the same time. However, clicking the Skip button fires the same action as the Continue button, as displayed in the JS code below. I'd like the action to only Fire when the Skip button is clicked but it keeps firing on both and I cant figure out how to figure it out.
I'd like a certain action to fire but only fire when <a class="introjs-button introjs-skipbutton> is fired and NOT <a class="introjs-button introjs-skipbutton introjs-donebutton> is fired.
$("a.introjs-button.introjs-skipbutton").not(".introjs-donebutton").click(() => {
console.log('skipbuttontriggered')
this._app.skipTutorial = true;
})
I've tried various combinations and was hoping to get some insight on using the not() selector for triple stacked html classes.

You don't need to use :not(). You could just check it doesn't have the class.
$("a.introjs-button.introjs-skipbutton").click(() => {
if ( ! $(this).hasClass('introjs-donebutton') {
console.log('skipbuttontriggered')
this._app.skipTutorial = true;
}
})
The hasClass() documentation can be read here.

If you're adding and removing the introjs-donebutton class dynamically, you can do it with event delegation and a selector with :not().
$(document).on("click", "a.introjs-button.introjs-skipbutton:not(.introjs-donebutton)", () => {
console.log('skipbuttontriggered')
this._app.skipTutorial = true;
})

Related

Trying to manipulating classes with JS to get a div element to close

I'm in the process of creating a web app that tracks real estate transactions. Part of that process is to track all the offers that come in on a specific property. An overview of the offers are displayed at first glance vertically on the page. When you click on an offer a control panel drops so that further info and/or actions can be viewed/taken. The code to drop the control panel is working and I've also got it so that if you click on another offer it closes any open control panels.
I've also included a div that I've given the class name of "close-bttn". This button is located within the main control-panel and is supposed to close the control-panel that it is a child of.
The close-bttn is supposed to close the open control panel, but it does not.
Here's a code shot of the structure
<div class="offer">
<div id="offer-amount"># dollarformat( offer_amount )#</div>
<div id="buyer-premium"># dollarFormat( buyer_premium )#</div>
<div id="buyer-name"># buyer_name #</div>
<div id="agent-name"># agent #</div>
<div id="agent-email"># agent_email #</div>
<div class="control-panel">
<div class="close-bttn">X</div>
</div>
</div>
Here is the code that I'm using to manipulate the elements
const eachOffer = document.querySelectorAll(".each-offer");
const controlPanels = document.querySelectorAll(".control-panel");
// This adds a click event to the <div class="offer"> element that opens the control-panel div
// by adding the class "scaley". The scaley class definition: .scaley{transform: scaleY(1)}
eachOffer.forEach((offer)=>{
// This. targets the specific control-panel for the offer
var o = offer.querySelector(".control-panel");
offer.addEventListener('click', ()=>{
// See function for explanation
// This closes any open control-panels
toggleControlPanel()
o.classList.toggle("scaley")
})
})
function toggleControlPanel(){
//There are multiple control-panels, one for each offer. This loops over all the control-panels
// on the page and if the classList contains "scaley" it is removed which closes the ocntrol-panel
document.querySelectorAll(".control-panel").forEach((o)=>{
if( o.classList.contains("scaley") ) o.classList.toggle("scaley")
});
}//END
Here's the code to add the click event to use the close-bttn to close the control-panel
controlPanels.forEach((panel)=>{
panel.querySelector(".close-bttn").addEventListener("click",()=>{
//This does not seem to be working.
// I've tried to use classList.toggle as well with no result
panel.classList.remove("scaley")
})
})
Not sure what to do here. Any ideas??
In addition I've used
classList.toggle
classList.remove
classList.value
//ClassList.value contains all the classes an element has
//So the control-panel has a classList.value="control-panel scaley" at onset
//I tried to do classList.value="control-panel". that didn't work.
Here is a link to a codepn example that I posted: https://codepen.io/Hugh-Rainey/pen/wvxjgpJ?editors=1111
Your remove() function is working, only problem is your click event is bubbling up and triggering the handler on your offer divs (which re-toggles them back open). You need to stop the event from bubbling up.
controlPanels.forEach((panel)=>{
panel.querySelector(".close-bttn").addEventListener("click",(e)=>{
e.stopPropagation(); // stop event bubbling, don't forget to add e to your param list
panel.classList.remove("scaley")
})
})
querySelectorAll returns a NodeListOf which is not an array. So use a for loop like this:
for (let i = 0; i < controlPanels.length; i++) {
panel.querySelector(".close-bttn").addEventListener("click",()=>{
panel.classList.remove("scaley")
})
}

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

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);

jQuery - .on('click') not working on <li>

so I've been tasked with making a website using Wordpress and on the homepage there's a slider that if you click on the buttons below, it's displays another image, simple right? Well, I've got the slider and I've got the buttons, I've added the jQuery and it doesn't want to work.
I first tried making the buttons actually buttons:
<button type="button" class="btn btn-success" id="hideshow-healthcare">Healthcare</button>
and that worked fine when I used this:
jQuery(document).ready(function() {
jQuery('#hideshow-healthcare').on('click', function() {
jQuery('#healthcare').show();
};
};
So after having it working like that, I moved on to making the buttons in to li's instead so that I could follow the design. Upon doing this, the slider no longer works. I've tried mulitple different things including adding the ID to everything in the li to see if that would work, and sadly not. I did some research and tried to change
jQuery('#hideshow-healthcare').on('click', function() {
to
jQuery('li#hideshow-healthcare').on('click', function() {
but still, no luck. I was hoping someone would be able to provide a solution to this problem.
Also, this is the li code I'm currently using:
<li><a id="hideshow-healthcare"><h5>HEALTHCARE</h5> Lighting to create a feeling of well being</a></li>
You need to add space after li element to find its descendants #hideshow-healthcare. It should be
jQuery('li #hideshow-healthcare').on('click', function() {
#hideshow-healthcare is child of li. Use descendant selector in jquery
jQuery('li a#hideshow-healthcare').on('click', function(event) {
event.preventDefault(); // prevents default action
// your code
});
Id be unique in html you just straightly write with id
jQuery('#hideshow-healthcare').on('click', function(event) {
event.preventDefault(); // prevents default action
// your code
});

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();
}
});

jQuery .on('click') firing multiple times when used with :not() selector

Good morning,
I have a set of boxes on a page that are presented as a list, and within these boxes there might be some links that can be clicked. I want the links within the boxes to work as normal (i.e. bubble up and either perform the default action or then be handled by event handlers further up the DOM), but if the box is clicked anywhere else then it should be caught by a particular event handler attached to the "list" containing all the boxes.
Simple html representation
<div class="boxlist">
<div class="box" data-boxid="1">
Some text, and possibly a link and another link, and perhaps even a third link.
</div>
<div class="box" data-boxid="2">
Some more text, this time without a link.
</div>
</div>
The javascript that I thought should work.
$(function () {
$('.boxlist').on('click', '.box :not(a)', function (e) {
var boxid= $(this).closest('.box').data('boxid');
console.log('open: ' + boxid);
});
});
My expectation was that the above javascript should handle all clicks that did not originate from tags. However, for some reason when the box is clicked (either the box itself, or an tag, doesn't matter), it fires this event X times, where X is the total number of tags within the list of boxes.
So I have two questions:
1. What am I doing wrong with the :not() selector.
2. Is there a better way to handle this scenario?
Thank you for helping!
linkUsing jQuery :not selector actually is very slow ex:http://jsperf.com/not-vs-notdasdsad/4 and it's way better to just use event delegation. So in this case you want to keep track of every click on the .boxlist but check the node type to see if its an anchor or not. This is an example.
$(function () {
$('.boxlist').on('click', function(ev){
if(ev.target.tagName != "A"){
// handle box click code
console.log('box click');
return false;
}
// Otherwise allow event to bubble through.
});
});
and here is a jsfiddle example
http://jsfiddle.net/drXmA/
Also their are a few reasons your code doesn't work
.box :not(a)
should be
.box:not(a)
and the reason this also does not work is because .box is not an anchor tag it has children elements that are anchor tags it will never find an anchor tag named .box if their is one the callback would not execute. Changing the .box to an anchor tag will make it so the code doesn't execute because .box is an anchor and it is only running when .box:not(a)
I guess you want something like this:
$('.boxlist').on('click', '.box:not(a)', function (e) {
var boxid = $(this).closest('.box').data('boxid');
console.log('open: ' + boxid);
}).on('click', '.box a', function (e) {
e.preventDefault().stopPropagation();
});
DEMO FIDDLE
I think better to stop the default behavior and stop the event bubbling to its parent. .on() chain to the .box items excluding <a> from it and stop the default behavior and event bubble with e.preventDefault().stopPropagation();

Categories

Resources