I am developing a website and I can't use jQuery (no discussion about this), so pure javascript and a custom javascript framework is used.
Actually I have found a situation that I don't know how to handle:
I've a group of selectors, that for each one I add a "onclick" event to display / hide a div.
For example:
<div id="menu">
<div class="menu-item">
<div class="arrow">
<a class="down">Open / Close</a>
</div>
Menu Item
<div class="extramenu hidden">
Extra menu items
</div>
</div>
<div class="menu-item">
<div class="arrow">
<a class="up">Open / Close</a>
</div>
Menu Item 2
<div class="extramenu">
Extra menu items
</div>
</div>
<div class="menu-item">
<div class="arrow">
<a class="down">Open / Close</a>
</div>
Menu Item 3
<div class="extramenu hidden">
Extra menu items
</div>
</div>
</div>
I select all "div.menu-item .arrow a" items, so I've 3 items. For each item I add a onclick event (that actually works fine).
What I need to archive is how to select the "closest" class .extramenu inside the div.menu-item. Then detect if the <a /> have a class .up or .down and if class == .up, add the class hidden; and if class == .down, remove the class hidden.
This a concept of what have to do, it's not javascript code:
var elements; // my list of elements
each(elements, function(element) {
// here element is pointing to the ANCHOR
add_event(element, "onclick", function(e) {
var submenu; // here I need to detect the submenu closest to my anchor
var state; // here I need to know if the anchor has class up or down
if (state == "up")
{
add_class(submenu, "hidden"); // hide the submenu div
remove_class(element, "up"); // remove the class up
add_class(element, "down"); // and add the class down
}
else if (state == "down")
{
remove_class(submenu, "hidden"); // remove the class to show the menu
remove_class(element, "down"); // remove the class down
add_class(element, "up"); // and add the class up
}
});
});
Thank you guys and sorry if it's not well explained, I did my best!
element.querySelectorAll allows you to select elements by CSS selector.
element.classList allows you to access the classes of an element
add_event(element, "onclick", function(e) {
var el = e.target, state;
var parent = el.parentNode;
while (!parent.classList.contains('menu-item')) {
parent = parent.parentNode;
}
var submenu = parent.querySelector('extramenu');
if (el.classList.contains('up')) {
state = 'up';
} else {
state = 'down'
}
/* ... */
});
You can write the rest of the pseudo code yourself.
I'm assuming your already using Modernizr for supporting legacy browsers like IE8. If your not, then do so.
Maybe not exactly the way you want to do this but if class up or down would be added to parent of the a ie div.arrow you could do all of the hiding/showing with css combinator +. like this:
.arrow.down + .extramenu {
/* the same styles as with hidden class */
}
This is the code you are looking for. Tested in FF5, should be cross-browser.
// use in your add_event function
var submenu = element.parentNode.nextSibling;
while(submenu && (submenu.nodeName!="DIV" || submenu.className.indexOf("extramenu")==-1)) submenu = submenu.nextSibling;
var state = element.className;
Related
I have an issue and I don't know how I can fix this and I need some help.
The following code I have so far
<div class="parent" data="one">
<div class="child hide" id="one">
test
</div>
</div>
<div class="parent" data="two">
<div class="child hide" id='two'>
test 2
</div>
</div>
var parent = document.getElementsByClassName("parent");
for (var i = 0; i < parent.length; i++) {
parent[i].addEventListener("click", function () {
var child = document.getElementsByClassName("child");
var attribute = this.getAttribute("data");
var the_element = document.getElementById(attribute);
for (var is = 0; is < child.length; is++) {
child[is].classList.add('hide');
child[is].classList.remove('show');
}
the_element.classList.add('show');
});
}
If the user click on the parent the child what is connected get the class show and the hide class is removed. If the user click on another parent all child elements get the class hide en the show class is removed. The code above works for this but what I also want is if the user clicks on the parent and after that the user clicks the same parent the class show remove and add hide at the child.
I think I must use this in JavaScript but how can I combine this all together?
You can toggle element using just adding 'hide' class. Add css classes as below.
<style>
.parent {
...
}
.child {
...
}
.hide {
display: none;
}
</style>
Add html elements as below.
<div class="parent" data="one">
<div class="child hide" id="one">
test
</div>
</div>
<div class="parent" data="two">
<div class="child hide" id='two'>
test 2
</div>
</div>
Then add javascript to toggle elements.
<script>
// Get parent elements and children elements
let parents = document.getElementsByClassName("parent");
let children = document.getElementsByClassName("child");
// Form an Array with parent elements and
// add event listener for each parent
Array.from(parents).forEach(parent => {
parent.addEventListener("click", function () {
// Form an Array with child elements and
// check condition for each children
Array.from(children).forEach(child => {
// Check wheather is it the child of clicked parent
if(child.parentNode == this) {
// If clicked parent's child just toggle hide class
child.classList.toggle("hide");
}else {
// Add hide class for all other children
child.classList.add("hide");
}
});
});
});
</script>
Thats it! Hope it helps.
I'm building a carousel with basic jquery - I'm using the .css() rule to simply toggle opacity between each slide.
The way I want to do this is on click of each dot I want to check if the specific class exists and if it does hide all other items and show that one. So far I have:
$('.dot').click(function() {
$('.review-module--reviews').children().css('opacity', 0);
if ($('.dot').hasClass('dot1')) {
$('.review-one').css('opacity', 1);
$('.dot1').addClass('dot-active');
} else if ($('.dot').hasClass('dot2')) {
$('.review-two').css('opacity', 1);
$('.dot2').addClass('dot-active');
} else {
$('.review-three').css('opacity', 1);
$('.dot3').addClass('dot-active');
}
});
HTML:
<div class="review-module">
<div class="review-module--reviews">
<div class="review-one">
</div>
<div class="review-two">
</div>
<div class="review-three">
</div>
</div>
<span class="slider-dots">
<div class="dot dot1"></div>
<div class="dot dot2"></div>
<div class="dot dot3"></div>
</span>
</div>
However when I click on dots 2 and 3, it always targets the dot1 slide in the DOM. The 'dot-active' class gets added successfully to dot1 but on click of 2 and 3, that class does not get added.
I also tried explicity checking for a true value in the if statement like so:
if ($('.dot').hasClass('dot1') === true)
Is this the best way to do this? Or should I consider a different thought process?
The error is in this code:
if ($('.dot').hasClass('dotX'))
What you're actually doing here is fetching the list of all .dot elements and checking if the first one has the dotX class. As you can imagine, this will always pick up the first .dot element, which has the dot1 class.
What you probably mean to do is to check if the element that was clicked on has the dotX class, for which you need to check only that element.
Either do so by using the current scope of the click handler:
if ($(this).hasClass('dotX'))
or by checking the target of the click event:
$('.dot').click(function(e) {
$('.review-module--reviews').children().css('opacity', 0);
if ($(e.target).hasClass('dot1')) {
Try this may be it can help you -
JAVASCRIPT CODE-
$('.dot').click(function() {
$('.review-module--reviews').children().css('opacity', 0);
$('.dot').removeClass('dot-active');
if ($(this).hasClass('dot1')) {
$('.review-one').css('opacity', 1);
$(this).addClass('dot-active');
} else if ($(this).hasClass('dot2')) {
$('.review-two').css('opacity', 1);
$(this).addClass('dot-active');
} else {
$('.review-three').css('opacity', 1);
$(this).addClass('dot-active');
}
});
I suggest to use data-* attributes instead so give every .dot a data-review that refer to the related review div :
$('.review-module--reviews div').hide(); //Hide all the slides
$('.dot').click(function() {
var review = $(this).data('review');
$('.review-module--reviews div').hide(); //Hide all slides
$('.slider-dots .dot').removeClass('dot-active'); //Remove 'dot-active' class from all the dots
$(this).addClass('dot-active'); //Active the clicked dot
$('.review-'+review).show(); //Show the related slide
});
Then on click just get the review using jQuery method .data() and show the div with related class.
Hope this helps.
$('.review-module--reviews div').hide();
$('.dot').click(function() {
var review = $(this).data('review');
$('.review-module--reviews div').hide();
$('.slider-dots .dot').removeClass('dot-active');
$(this).addClass('dot-active');
$('.review-'+review).show();
});
.dot-active{
color: green;
font-weight:bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="slider-dots">
<div class="dot dot1" data-review="one">dot1</div>
<div class="dot dot2" data-review="two">dot2</div>
<div class="dot dot3" data-review="three">dot3</div>
</span>
<br>
<div class="review-module">
<div class="review-module--reviews">
<div class="review-one">
Review-one
</div>
<div class="review-two">
Review-two
</div>
<div class="review-three">
Review-three
</div>
</div>
</div>
So I'm using classes to sort different content, but I'm not actually sure how to apply this sorting.
<div class="class1"><div class="heads">Title</div>
<div class="description"><p>Class 1 Item 1</p></div></div>
<div class="class2"><div class="heads">Title</div>
<div class="description"><p>Class 2 Item 1</p></div></div>
<div class="class2"><div class="heads">Title</div>
<div class="description"><p>Class 2 Item 2</p></div></div>
<div class="class3"><div class="heads">Title</div>
<div class="description"><p>Class 3 Item 1</p></div></div>
So let's say the user clicks a button that says 'Class 2'. I want the opacity of everything that is not class 2 to be, say, .5 while class 2's opacity stays at 1. I've tried using .not(), but I'm not familiar with it and most examples use it in conjunction with .siblings(), and I don't want the siblings to fade either. Help? I'm not sure what to do.
Edit: Sorry about the orphan s. ^_^; Fixed them!
http://jsfiddle.net/orjj65g0/7/
$("#container button").click(function() {
var className = $(this)[0].className;
$("#container button").each(function() {
if($(this)[0].className !== className) {
$(this).next().addClass("op05");
$(this).next().removeClass("op1");
} else {
$(this).next().addClass("op15");
$(this).next().removeClass("op05");
}
});
});
With $("#container button").click(...) you access every button in #container.
$(this).[0].className is the class name of the button you have clicked.
After you have clicked the button, you go through every button in the container:
$("#container button").each(...)
In the container you compare the class names with the clicked class name. If there are not the same, than add the class "op05" to the div after the button and remove the class "op1" from the div after the button:
(Example:
<button class="classN">click</button>
<div class="content">div after button</div>
$(".classN").next()...
)
Here:
$(this).next()...
And with all the div's after the button(s), that have the same class name happens the same with the 'opposite' class names.
$("div").not(".class2").css("opacity", "0.5")
will set opacity of all divs except for ones with class class2 to 0.5.
If you are using a container:
$('.container>div:not(.class2)').css('opacity', 0.5);
1. You have invalid HTML. a tag opening is missing. Based on my assumptions, that's how it should look like:
<div class="classX">
Title
</div>
<div class="description">
<p>Class X Item 1</p>
</div>
But it's very unintuitive syntax. What is .description content for? I suggest you to rewrite syntax. For example:
<div class="classX">
Title
<div class="description">
<p>Class X Item 1</p>
</div>
</div>
2. You can use .not() method or :not() selector in jQuery
According to my version of HTML. Let's code!
$("a").on('click', function(){
var $t = $(this).parent(); // clicked div.class2 for example
$t.css("opacity", 1).siblings().css("opacity", 1); // undo selection
$t.siblings().not("."+$t.attr("class")).css("opacity", 0.5);
// hide other classes. Equivalent with selector:
//$t.siblings(":not(."+$t.attr("class")+")").css("opacity", 0.5);
});
Check it that's what you want: http://jsfiddle.net/Tymek/2k85m8r9/
I am using a JavaScript function and some jQuery to perform two actions on a page. The first is a simple JS function to hide/show divs and change the active state of a tab:
This is the JS that show/hides divs and changes the active state on some tabs:
var ids=new Array('section1','section2','section3');
function switchid(id, el){
hideallids();
showdiv(id);
var li = el.parentNode.parentNode.childNodes[0];
while (li) {
if (!li.tagName || li.tagName.toLowerCase() != "li")
li = li.nextSibling; // skip the text node
if (li) {
li.className = "";
li = li.nextSibling;
}
}
el.parentNode.className = "active";
}
function hideallids(){
//loop through the array and hide each element by id
for (var i=0;i<ids.length;i++){
hidediv(ids[i]);
}
}
function hidediv(id) {
//safe function to hide an element with a specified id
document.getElementById(id).style.display = 'none';
}
function showdiv(id) {
//safe function to show an element with a specified id
document.getElementById(id).style.display = 'block';
}
The html:
<ul>
<li class="active"><a onclick="switchid('section1', this);return false;">ONE</a></li>
<li><a onclick="switchid('section2', this);return false;">TWO</a></li>
<li><a onclick="switchid('section3', this);return false;">THREE</a></li>
</ul>
<div id="section1" style="display:block;">TEST</div>
<div id="section2" style="display:none;">TEST 2</div>
<div id="section3" style="display:none;">TEST 3</div>
Now the problem....
I've added the jQuery image gallery called galleria to one of the tabs. The gallery works great when it resides in the div that is intially set to display:block. However, when it is in one of the divs that is set to display: none; part of the gallery doesn't work when the div is toggled to be visible. Specifically, the following css ceases to be written (this is created by galleria jQuery):
element.style {
display:block;
height:50px;
margin-left:-17px;
width:auto;
}
For the life of me, I can't figure out why the gallery fails when it's div is set to display: none. Since this declaration is overwritten when a tab is clicked (via the Javascript functions above), why would this cause a problem? As I mentioned, it works perfectly when it lives the in display: block; div.
Any ideas? I don't expect anybody to be familiar with the jQuery galleria image gallery... but perhaps an idea of how one might repair this problem?
Thanks!
If you are including jQuery then you can shorten your javascript to this:
$(function() {
var sections = $('#section1, #section2, #section3');
function switchid(id, el){
sections.hide();
$('#'+id).show();
$(this).addClass('active').closest('ul').find('li').removeClass('active');
}
});
I would also remove the inline styles that set display:none. Then you can in your javascript you can initialize galleria then hide your sections.
Something like:
$(function() {
$('#section2, #section3').hide();
$('#section2 .images').galleria();
var sections = $('#section1, #section2, #section3');
function switchid(id, el){
sections.hide();
$('#'+id).show();
$(this).addClass('active').closest('ul').find('li').removeClass('active');
}
});
I would even go further and change your html to be something like this:
<ul class="sectionlinks">
<li class="active">ONE</li>
<li>TWO</li>
<li>THREE</li>
</ul>
<div id="section1" class="section">TEST</div>
<div id="section2" class="section">TEST 2</div>
<div id="section3" class="section">TEST 3</div>
Then you javascript could just be:
$(function() {
$('#section2 .images').galleria();
$('#section2, #section3').hide();
var sections = $('.section');
$('.sectionlinks a').click(function(e){
e.preventDefault();
sections.hide();
$($(this).attr('href')).show();
$(this).closest('ul').find('li').removeClass('active');
$(this).closest('li').addClass('active');
});
});
Working example: http://jsfiddle.net/cdaRu/2/
Set them all to 'block' by default, initialize the galleria image gallery, and afterwards hide the divs you want hidden and see if that fixes it. Or try initializing the gallery again after every switchid.
My first recommendation would be to re-write your original Javascript function to use jQuery. It already has built-in visibility toggle functions ... using the same system will minimize conflicts and make for smoother code.
This is just "off the cuff" but perhaps the box model is incomplete: "The element will generate no box at all" with display: none;
Perhaps change that back to "block" and set visibility: hidden; would be better?
I have a number of dropdowns and divs that are hidden when the page loads and can be toggled with a click or mouseover, but some of them flash b/c the JavaScript does not run in time. I have their display initially set to block and then I use JavaScript/prototype to find the element and hide it. I have tried loading these "hider" functions using dom:loaded but there is still flashing. This is an example of a dropdown prototype initialization function. From
http://www.makesites.cc/programming/by-makis/simple-drop-down-menu-with-prototype/:
var DropDownMenu = Class.create();
DropDownMenu.prototype = {
initialize: function(menuElement) {
menuElement.childElements().each(function(node){
// if there is a submenu
var submenu = $A(node.getElementsByTagName("ul")).first();
if(submenu != null){
// make sub-menu invisible
Element.extend(submenu).setStyle({display: 'none'});
// toggle the visibility of the submenu
node.onmouseover = node.onmouseout = function(){
Element.toggle(submenu);
}
}
});
}
};
Is there a better way to hide div's or dropdowns to avoid this flashing?
You always run the risk of flicker when you try to hide elements after page load.
I suggest you give the elements in question an inline style like display:none; or a css class with the same setting.
From the class creation syntax used, I take it that you are using something like Prototype version 1.5.x. Here's my take on how I'd do it with that version (it would be nicer to step up to the latest version, of course):
<script type="text/javascript">
var DropDownMenu = Class.create();
DropDownMenu.prototype = {
initialize: function(menuElement) {
// Instead of using 2 listeners for every menu, listen for
// mouse-ing on the menu-container itself.
// Then, find the actual menu to toggle when handling the event.
$(menuElement).observe('mouseout', DropDownMenu.menuToggle);
$(menuElement).observe('mouseover', DropDownMenu.menuToggle);
}
};
DropDownMenu.menuToggle = function (event) {
var menu = DropDownMenu._findMenuElement(event);
if (menu) {Element.toggle(menu);}
};
DropDownMenu._findMenuElement = function (event) {
var element = Event.element(event);
return Element.down(element, 'ul');
}
var toggler = new DropDownMenu('menus');
</script>
And here is some markup to test it with (it may not match yours perfectly, but I think it is similar enough):
<html>
<head>
<title>menu stuff</title>
<style type="text/css ">
/* minimal css */
#menus ul, .menu-type {float: left;width: 10em;}
</style>
</head>
<body>
<h1>Menus</h1>
<div id="menus">
<div class="menu-type">
Numeric
<ul style="display: none;">
<li>1</li><li>2</li><li>3</li><li>4</li>
</ul>
</div>
<div class="menu-type">
Alpha
<ul style="display: none;">
<li>a</li><li>b</li><li>c</li><li>d</li>
</ul>
</div>
<div class="menu-type">
Roman
<ul style="display: none;">
<li>I</li><li>II</li><li>III</li><li>IV</li>
</ul>
</div>
</div>
</body>
</html>
Yoda voice: "Include the prototype.js, I forgot."
Should you want to get rid of inline styling (like I do), give the uls a class like
.hidden {display:none;}
instead, and make the DropDownMenu.menuToggle function do this
if (menu) {Element.toggleClassName(menu, 'hidden');}
instead of toggling the display property directly.
Hope this helps.
Set the display initially to none, then show them as needed. That will get rid of the flashing.