When I click a button div, I want to add a class named active to the popup div that has the corresponding class name in the data-trigger attribute.
For example if I click on the div with class name button-two, the div with data-trigger="button-two" should get class active.
The issue: active is added only to the last popup div. How can I make this work?
Here's what I have tried:
$('.popup').each(function() {
popupObj = $(this);
var popupTrigger = popupObj.data("trigger");
$('.' + popupTrigger).click(function() {
popupObj.addClass('active');
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="button-one">Test 1</div>
<div class="button-two">Test 2</div>
<div class="button-three">Test 3</div>
<div class="popup" data-trigger="button-one">Hello world</div>
<div class="popup" data-trigger="button-two">Hello there</div>
<div class="popup" data-trigger="button-three">Hello again</div>
This is because you did not declare popupObj as a local variable; It is global, and so it will have changed in the last iteration of the each: it is that value that will be referenced in all three click handlers.
Remember that each will have performed all iterations before any of the click handlers get called.
Solution: use var popupObj. That way each of the click handlers will reference their "own" variable.
Simple way to use data attribute also for buttons .. and make only one click event for the buttons .. see the next example
$('.button[data-to-trigger]').on('click' , function(){
var GetTriggerDiv = $(this).attr('data-to-trigger');
$('.popup').removeClass('active').filter('.popup[data-trigger="'+GetTriggerDiv+'"]').addClass('active');
});
.active{
background : red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="button" data-to-trigger="button-one">Test 1</div>
<div class="button" data-to-trigger="button-two">Test 2</div>
<div class="button" data-to-trigger="button-three">Test 3</div>
<div class="popup" data-trigger="button-one">Hello world</div>
<div class="popup" data-trigger="button-two">Hello there</div>
<div class="popup" data-trigger="button-three">Hello again</div>
The "each" function in jQuery returns 2 values: index and element. Try using the element returned instead of $(this).
$('.popup').each(function(index, element) {
var popupTrigger = element.data("trigger");
$('.'+popupTrigger).click(function() {
element.addClass('active');
});
});
Here's a solution that matches the popup to the button using the same data trigger for both:
$(document).ready(function() {
$(".btn").click(function() {
var trigger = $(this).data("trigger");
$('.popup').each(function() {
if ($(this).data("trigger") == trigger) {
$(this).addClass('active');
} else {
$(this).removeClass('active');
}
});
});
});
.active {
background-color: coral;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="btn" data-trigger="button-one">Test 1</div>
<div class="btn" data-trigger="button-two">Test 2</div>
<div class="btn" data-trigger="button-three">Test 3</div>
<div class="popup" data-trigger="button-one">Hello world</div>
<div class="popup" data-trigger="button-two">Hello there</div>
<div class="popup" data-trigger="button-three">Hello again</div>
Related
HTML:
<div id="div1">
<div class="close">close</div>
</div>
<div id="div2">
<div class="close">close</div>
</div>
jQuery:
$('.close').on('click', '#div1, #div2', function(){
console.log ( $(this) ); // .close
});
If I have multiple elements with close buttons, how do I get the parent element as this and not the button?
So if I click the .close on #div1, I need #div1 as this to work with it.
By instinct, I would look to closest, which takes a selector as a param:
var selector = '#div1, #div2';
$('.close').on('click', selector, function(){
console.log ( $(this).closest(selector) ); // .close
});
.closest will return a jQuery object representing first node that matches the selector. It starts with the current object and continues to .parent() until it finds a match
since the element is a child of the element you want to reference, use a parent selector.
$(this).parent().hide()
Most of the time we would use a class on the element and use closest to select it.
$(this).closest('.msg').hide()
$('.close').on('click', function(){
$(this).closest(".msg").hide();
});
.msg{
.border: 1px solid black
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div1" class="msg">
<div class="close">close</div>
<p>test 1</p>
</div>
<div id="div2" class="msg">
<div class="close">close</div>
<p>test 2</p>
</div>
You actually don't need any selector, just a .closest("div").
If you want to be a bit more specific like "The closest ID starts with div" than you could do like:
$('.close').on('click', function(){
$(this).closest("[id^='div']").fadeOut();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div1">
<div class="close">close1</div>
</div>
<div id="div2">
<div class="close">close2</div>
</div>
Or, by doing it the way you started you could use the event.delegateTarget -
which refers to the actual selector-delegators $('#div1, #div2')
$('#div1, #div2').on('click', '.close', function(event) {
$(event.delegateTarget).fadeOut();
});
// or use also for brevity:
// $("[id^='div']").on(...
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div1">
<div class="close">close1</div>
</div>
<div id="div2">
<div class="close">close2</div>
</div>
I want to traverse through pages and toggle active class through them. How should I do this without using set class?
HTML
<div class="page active"></div>
<div class="set">
<div class="page"></div>
<div class="page"></div>
</div>
<div class="page"></div>
jQuery
$('.active').toggleClass('active').toggle().nextAll('.page').toggleClass('active');
I am assuming that by "traverse" you mean you want to toggle the .page divs one by one in a certain order.
If that is the case, write an algorithm that traverses a tree: given a root, toggle if it is a .page, and recursively deal with each of its children
function traverse(root){
if(!root) return;
if(root.hasClass('page')) root.toggle('active');
root.children().forEach(function(child){
traverse(child);
});
//lets say you want to bind to click event on every div
$('div').click(function(){
traverse($(this));
});
}
Unfortunately we don't have a direct way to find the next non sibling element, but we can handle that situation in many ways using jquery functions. I just tried on way to achieve your goal, check out this working fiddle and let me know if you need any clarity, added some inline comments also for your understanding.
HTML:
<div class="page active">div 1</div>
<div class="page">div 2</div>
<div class="set">
<div class="page">set 1 - div 1</div>
<div class="page">set 1 - div 2</div>
<div class="page">set 1 - div 3</div>
</div>
<div class="page">div 5</div>
<div class="set">
<div class="page">set 2 - div 1</div>
<div class="page">set 2 - div 2</div>
</div>
<div class="page">div 6</div>
<button class="next-btn">Next</button>
CSS:
.active {
color: red;
}
.next-btn {
cursor: pointer;
}
Javascript:
$(function() {
$('button').click(function() {
var elem = $(".page.active").toggleClass('active'); // current active element
var nextElem = elem.next(); // next element
// go above one level and get next element
// if no next element exists, means end of the child level
if (!nextElem.length) {
nextElem = elem.parent().next();
}
// if next element has some PAGE children then update the first child element
if (nextElem.children('.page').length > 0 ) {
nextElem.children('.page:first-child').toggleClass('active');
} else if (nextElem.hasClass('page')) {
nextElem.toggleClass('active');
}
});
});
This approach handles the scenario with one child level, you can extend this to multiple levels also with recursive functions, I think this helps you to handle your scenario accordingly.
Working fiddle
You could achieve that using indexes to get the next element in the DOM using the index of active one +1 then active it, I think the following is what you are looking for:
var getActiveIndex = function(){
var active_index;
$('.page').each(function(i){
if ( $(this).hasClass('active') )
active_index = i;
})
return active_index;
}
$('body').on('click', '.next', function(){
var active_page_index = getActiveIndex(); //Get active page index
var new_index = active_page_index+1; //Set the next page index
var next_page = $('.page:eq('+new_index+')'); //Get the next page
$('.page').removeClass('active');
if(next_page.length)
next_page.addClass('active');
else
$('.page:first').addClass('active');
})
I hope this helps.
var getActiveIndex = function(){
var active_index;
$('.page').each(function(i){
if ( $(this).hasClass('active') )
active_index = i;
})
return active_index;
}
$('body').on('click', '.next', function(){
var active_page_index=getActiveIndex();
var new_index = active_page_index+1;
var next_page = $('.page:eq('+new_index+')');
$('.page').removeClass('active');
if(next_page.length)
next_page.addClass('active');
else
$('.page:first').addClass('active');
})
.active{
background-color: red;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="page active">page</div>
<div class="set">
<div class="page">- Set page</div>
<div class="page">- Set page</div>
</div>
<div class="page">page</div>
<div class="page">page</div>
<div class="page">page</div>
<div class="set">
<div class="page">- Set page</div>
<div class="page">- Set page</div>
</div>
<div class="page">page</div>
<br>
<button class='next'>Active the next page</button>
HTML:
<div class="outer">
<div id="inner1" class="inner" style="display: none"></div>
<div id="inner2" class="inner"></div>
<div id="inner3" class="inner"></div>
</div>
JavaScript (fiddle):
var $first_visible = $("div.inner:visible:first");
This returns the first visible inner div, which is inner2.
However, as soon as the outer div is hidden (let's say I want to fade it in at some later time):
<div class="outer" style="display: none">
<div id="inner1" class="inner" style="display: none"></div>
<div id="inner2" class="inner"></div>
<div id="inner3" class="inner"></div>
</div>
all inner divs are considered hidden and the selector does not return inner2 any more.
How would I need to modify my jQuery selector to ignore the container's visibility?
As adeneo said, once its hidden, there isnt much you can do.
However, you can check before hand, show it regardless, then hide it again if it was hidden
var wasVisible = $(".outer").is(':visible');
$(".outer").show();
var $first_visible = $("div.inner:visible:first");
if (!wasVisible) {
$(".outer").hide();
}
console.log($first_visible.length);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="outer" style="display: none">
<div id="inner1" class="inner" style="display: none"></div>
<div id="inner2" class="inner"></div>
<div id="inner3" class="inner"></div>
</div>
MDN says:
When you use none, all descendant elements also have their display turned off. The document is rendered as though the element doesn't exist in the document tree.
Hence, whatever the HTML elements are child to the parent element will not be rendered in the HTML page.
And moreover, whatever styles that has been applied on the parent element will not be rendered in HTML page.
In order to achieve what you want and if you consider that your HTML element should be in the document tree then try using CSS visibility property. For example:
<div class="outer" style="visibility: hidden">
<div id="inner1" class="inner" style="display: none"></div>
<div id="inner2" class="inner" style="visibility: visible"></div>
<div id="inner3" class="inner"></div>
</div>
JS Fiddle
If I understood you correctly, you can simulate the effects of the parent being hidden using CSS like this.
HTML
<div class="outer hide">
<div id="inner1" class="inner hide">Inner 1</div>
<div id="inner2" class="inner">Inner 2</div>
<div id="inner3" class="inner">Inner 3</div>
</div>
CSS
.hide {
background: rgba(0,0,0,0);
color: rgba(0,0,0,0);
border-color: rgba(0,0,0,0);
// For an SVG
fill: rgba(0,0,0,0);
stroke-opacity: 0;
}
The reason why you can't use the visibility/display/opacity property is because as #Umesh mentioned that the all descendant elements will also get their display/visibility/opacity as not visible as if the element doesn't exist in the document tree.
But using this method you set the alpha to 0 of the element and this doesn't effect the descendants unless they have inherit set for those properties.
Hope this helps.
write two classes : first one to display and last one to hide.
With that you can select all divs whoses "visible" even if parent is "hidden"
var $first_visible = $("div.inner.enable");
console.log($first_visible);
$("div#result").text($first_visible[0].id);
.disable{
display : none;
}
.enable{
display : block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer disable">
<div id="inner1" class="inner disable">1</div>
<div id="inner2" class="inner enable">2</div>
<div id="inner3" class="inner enable">3</div>
</div>
<div id="result"></div>
One option would be to show the parent element, check for the first visible element, and then hide the parent element again.
Alternatively, since the element has inline CSS, you could filter the elements based on whether the display property is set to none and then retrieve the first one in the filtered collection:
Updated Example
var $first_visible = $(".inner").filter(function () {
return this.style.display !== 'none';
}).first();
var $first_visible = $(".inner").filter(function () {
return this.style.display !== 'none';
}).first();
$("div#result").text('First visible: #' + $first_visible[0].id);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer" style="display: none;">
<div id="inner1" class="inner" style="display: none"></div>
<div id="inner2" class="inner"></div>
<div id="inner3" class="inner"></div>
</div>
<div id="result"></div>
However, the better approach would be to check the computed style of the element using the .getComputedStyle() method. In doing so, you can determine whether the display of the element is set to none even if the element doesn't have inline CSS.
Updated Example
var $first_visible = $(".inner").filter(function () {
return window.getComputedStyle(this, null).getPropertyValue('display') !== 'none';
}).first();
var $first_visible = $(".inner").filter(function () {
return window.getComputedStyle(this, null).getPropertyValue('display') !== 'none';
}).first();
$("div#result").text('First visible: #' + $first_visible[0].id);
#inner1 { display: none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer" style="display: none;">
<div id="inner1" class="inner"></div>
<div id="inner2" class="inner"></div>
<div id="inner3" class="inner"></div>
</div>
<div id="result"></div>
My proposal is to use a filter function but only to select the first visible element (but this is also hidden because the parent is hidden):
var $first_visible = $('div.inner').filter(function() {
return !(this.style.visibility != '' || this.style.display != '');
}).first();
$(function () {
var $first_visible = $('div.inner').filter(function() {
return !(this.style.visibility != '' || this.style.display != '');
}).first();
$('body').append('<p>' + $first_visible.attr('id') + '</p>');
});
<script src="http://code.jquery.com/jquery-1.11.3.js"></script>
<div class="outer" style="display: none">
<div id="inner1" class="inner" style="display: none;"></div>
<div id="inner2" class="inner"></div>
<div id="inner3" class="inner"></div>
</div>
See here i have checked style attribute for ignore first div. And check with hidden selector for get all other div.
$(document).ready(function(){
var currElements=$('.inner[style!="display: none"]:hidden'); // Here you are get two div with id inner2 and inner3
alert(currElements[0].id); // First div
alert(currElements[1].id); // First div
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer" style="display: none">
<div id="inner1" class="inner" style="display: none">Inner 1</div>
<div id="inner2" class="inner">Inner 2</div>
<div id="inner3" class="inner">Inner 3</div>
</div>
Take a flag value and loop each div.inner to get first visible element. Then check its css property.
Below is the tested code :
var isValid=true;
$("div.inner").each(function() {
if($(this).css("display") == "block" && isValid) {
$("div#result").text($(this).attr('id'));isValid=false;
}
});
So I have this menu:
<div class="default">Text 1</div>
<div class="default">Text 2</div>
<div class="default">Text 3</div>
And this iFrame:
<iframe src="splash.html" id="change_frame" name="change_frame" style="border-width:0;" width="100%" height="100%" frameborder="0" scrolling="no"></iframe>
What I want: when people click on one of those links in the menu, I want to add or remove a class. Here's an example to make it easier to understand:
When they click on text 1, the code should look like this:
<div class="default active">Text 1</div>
<div class="default">Text 2</div>
<div class="default">Text 3</div>
And then, if they click on text 2, the active class should be removed from text 1 and inserted on text 2, like this:
<div class="default">Text 1</div>
<div class="default active">Text 2</div>
<div class="default">Text 3</div>
Since the target is an iframe, I should probably use javascript, but I can't figure it out how. I know I wrote a bunch of code here, but I just wanna make myself clear. I searched everywhere but I couldn't find any solution.
If you're using jQuery, you can easily do that with click events and selectors.
$('.default').on('click', function() {
// Remove all active classes
$('.default').removeClass('active');
// Add an active class on the clicked element
$(this).addClass('active');
});
Demo here
select the <a> child of an element with default class ;
remove the active class from every element with default class ;
apply the active class to the parent element of the current <a>.
Demo:
$(function() {
$(".default > a").on("click keypress", function() {
$(".default").removeClass("active");
$(this).parent().addClass("active");
});
});
iframe {
height: 300px;
width: 100%;
}
.active:after {
color: red;
content: ' <- active!';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="default">Text 1
</div>
<div class="default">Text 2
</div>
<div class="default">Text 3
</div>
<iframe src="http://stackoverflow.com" id="change_frame" name="change_frame" frameborder="0" scrolling="no"></iframe>
When the a element is clicked you can use addClass to set the parent div as active. Try this:
$('.default a').click(function() {
$('.default').removeClass('active'); // remove the class from the current active div
$(this).closest('.default').addClass('active');
});
Example fiddle
JQuery, simply make your result in a better way.
$(document).ready(function(){
$(".default a").on("click",function(){
$(".default").removeClass("active");
$(this).parent(".default").addClass("active");
})
});
I have 20 rows of DIVs. The initial state hides all spoilers and is like below (I show the first 3 rows here):
<div class="main" onClick="showHide()">
some text 1
<div class="spoiler hide">spoiler</div>
</div>
<div class="main" onClick="showHide()">
some text 2
<div class="spoiler hide">spoiler 2</div>
</div>
<div class="main" onClick="showHide()">
some text 3
<div class="spoiler hide">spoiler 3</div>
</div>
etc..
CSS:
<style>
.main{background:silver;padding:1em;margin-bottom:1em}
.hide{display:none}
.show{display:block}
</style>
My goal is to manipulate/change the spoiler classes after user clicks on the "main" DIV. That is, after clicking on one of the "main" DIVs the "spoiler hide" class should automatically change to "spoiler show" so that the text is shown. And when user clicks on another "main" DIV, all 'spoiler show' classes should change to 'spoiler hide' and only the currently clicked "main" DIV should apply the 'spoiler show' class.
So it's basically like a toggle where only one (the last clicked) DIV shows the spoiler. I hope to find the simplest/fastest solution (JS in one line would work too).
I tried to use some JS function like below, but cannot make it work. I also read that 'document.querySelectorAll' might be used somehow.. I cannot use jQuery here.
<script>
function showHide() {
var e = document.getElementsByClassName('spoiler hide');
for(i=0; i<e.length; i++) {
e[i].className ='spoiler show';
}
}
</script>
Try this:
<script>
function showHide(sender) {
var e = sender.getElementsByClassName('spoiler hide');
for(i=0; i<e.length; i++)
{
e[i].className ='spoiler show';
}
}
</script>
<div class="main" onclick="showHide(this)">
some text 1
<div class="spoiler hide">spoiler</div>
</div>
<div class="main" onClick="showHide(this)">
some text 2
<div class="spoiler hide">spoiler 2</div>
</div>
<div class="main" onClick="showHide(this)">
some text 3
<div class="spoiler hide">spoiler 3</div>
</div>
Working fiddle here: http://jsfiddle.net/t0shq84f/