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?
Related
Sorry for the lack of knowledge but I don't know where else to turn. I had been working on the CSS for a project while the javascript was handled by a colleague. That colleague has now left the company and I have to finish his work to hit a deadline with very little knowledge of javascript. He had created a simple function (show/hide) that allowed us to show and hide content with an unordered list. Namely when you click on a list item, the corresponding div shows and the rest hides.
This was working fine, however I have since been asked to duplicate this so that multiple (show/hides) can be used on the page. When I did this the first one works ok, but the next scripts intefere with eachother and also hide content in the other divs. I've tried to fix this using my non-existent knowledge of javascript but to know avail (attempt is below). Any help here would be massively appreciated. Thanks in advance!
function toggle(target) {
var artz = document.getElementsByClassName('history');
var targ = document.getElementById(target);
var isVis = targ.style.display == 'block';
// hide all
for (var i = 0; i < artz.length; i++) {
artz[i].style.display = 'none';
}
// toggle current
targ.style.display = isVis? 'none' : 'block';
return false;
}
function toggle2(target) {
var artz2 = document.getElementsByClassName('vision');
var targ2 = document.getElementById(target2);
var isVis2 = targ.style.display == 'block';
// hide all
for (var i = 0; i < artz2.length; i++) {
artz2[i].style.display = 'none';
}
// toggle current
targ2.style.display = isVis2? 'none' : 'block';
return false;
}
jQuery(document).ready(function($) {
$('.slide-menu li a').on('click', function(){
$(this).parent().addClass('current').siblings().removeClass('current');
});
});
.container {
float: left;
}
.display-item {
display: none;
}
.display-item:first-of-type {
display: block;
}
.slide-menu li.current a {
color: #75aaaf;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div class="container">
<ul class="slide-menu" id="first">
<li class="current">1348</li>
<li>1558</li>
<li>1590</li>
</ul>
<div class="display-item history" id="1348" style="display:block;">History Content</div>
<div class="display-item history" id="1558">History Content2</div>
<div class="display-item history" id="1590">History Content3</div>
</div>
<div class="container">
<ul class="slide-menu" id="second">
<li class="current">Introduction</li>
<li>Highways</li>
<li>Transport</li>
</ul>
<div class="display-item vision" id="base" style="display:block;">Vision Content</div>
<div class="display-item vision" id="highways">Vision Content2</div>
<div class="display-item vision" id="transport">Vision Content3</div>
</div>
I think your code is okay if you intend duplicating the first toggle function in toggle2 function all you have to do is
Change the onclick event function from toggle to toggle2
<div class="container">
<ul class="slide-menu" id="second">
<li class="current"><a href="#/"
onclickk="toggle2('base');">Introduction</a></li>
<li><a href="#/"
onclick="toggle2('highways');">Highways</a></li>
<li><a href="#/"
onclick="toggle2('transport');">Transport</a></li>
</ul>
<div class="display-item vision" id="base"
style="display:block;">Vision Content</div>
<div class="display-item vision" id="highways">Vision
Content2</div>
<div class="display-item vision" id="transport">Vision
Content3</div>
</div>
This really isn't the way to set this up as it just causes the code to grow as more items need to be shown/hidden and the new code is largely the same as the old code. The original code also is more complex than it need be.
The following code will work no matter how many container structures you put on the page as long as you keep the structure the same as it is now. No ids are needed. No JQuery is needed either. You'll never need to touch the JavaScript, just add/remove HTML containers as you see fit.
See comments inline for details on what's happening.
.container {
float: left;
border:1px solid #e0e0e0;
margin:10px;
width:25%;
padding:3px;
}
/* Don't use hyperlinks <a></a> when you aren't
navigating anywhere. If you just need something
to click on, any element will do.
We'll just style the clickable elements to look like links
*/
.slide-menu > li {
text-decoration:underline;
cursor:pointer;
color: #75aaaf;
}
.hidden { display: none; } /* This class will be toggled upon clicks */
<!--
Don't use hyperlinks <a></a> when you aren't
navigating anywhere. If you just need something
to click on, any element will do.
The elements that should be hidden by default
will be so because of the "hidden" class that
they start off with.
No JQuery needed for this. Keep the HTML clean and
do all the event binding in JavaScript (no onclick="...")
-->
<div class="container">
<ul class="slide-menu">
<li class="current">1348</li>
<li>1558</li>
<li>1590</li>
</ul>
<div class="history" id="1348">History Content</div>
<div class="history hidden" id="1558">History Content2</div>
<div class="history hidden" id="1590">History Content3</div>
</div>
<div class="container">
<ul class="slide-menu">
<li class="current">Introduction</li>
<li>Highways</li>
<li>Transport</li>
</ul>
<div class="vision" id="base">Vision Content</div>
<div class="vision hidden" id="highways">Vision Content2</div>
<div class="vision hidden" id="transport">Vision Content3</div>
</div>
<!-- The following function will run automatically when this script element
is reached. Always keep the script just before the closing body tag (</body>). -->
<script>
(function(){
// Get any/all slide-menu elements into an array
let menus =Array.prototype.slice.call(document.querySelectorAll(".slide-menu"));
// Loop over the menus
menus.forEach(function(menu){
// Loop over the list items in the menu
Array.prototype.slice.call(menu.querySelectorAll("li")).forEach(function(item, index){
let idx = index;
// Set up a click event handler for each item
item.addEventListener("click", function(){
// Get all the <div> items in this menu into an Array
let divs = Array.prototype.slice.call(menu.parentElement.querySelectorAll("div"));
// Hide any item that was previously showing
divs.forEach(function(div){ div.classList.add("hidden"); });
// Query the parent element (the container) for all the
// corresponding <div> items and make it visible
divs[idx].classList.remove("hidden");
});
});
});
}());
</script>
I'm stuck with a jQuery issue that I don't manage to solve.
I've created a menu with sub menu elements. I would like to toggle the height of content by clicking in menu items. The thing is when I click on other item, the content collapse. Kind of tricky to explain, I've put two websites doing the job
http://www.polerstuff.com/ -> When you click on 'shop' and then on 'info', the sub menu stays open. The same trick was seen here http://topodesigns.com/
I guess these two websites are using Shopify.
$(document).ready(function() {
$(".button").on("click", function() {
if($(".content").height() == 0) {
$(".content").animate({height: "300px"});
}
else if($(".content").height() == 300) {
$(".content").animate({height: "0px"});
}
});
});
Here is my jsfiddle
-> Thank a lot in advance.
Here's version of your fiddle that uses the data attribute to target divs with desired content, and another data tag containing desired heights to animate (but there are many other ways).
Clicking on the same button toggles it shut, this is achieved by adding an indicative class.
The 'hiding' divs may contain further divs with classes and layout as required.
$(document).ready(function (){
$(".b").on("click", function (){
var $this = $(this),
target = $this.data('target'),
tall = $this.data('tall'),
content = $(".content");
target = $('.'+target).html(); // get the html content of target divs
content.html(target); // insert said content
if (!$this.hasClass('on')) { // if it hasn't been clicked yet..
$(".b").removeClass('on'); // say that none have been clicked
$this.addClass('on'); // say that just this one has been clicked
content.animate({height: tall}, 200); // animate to the height specified in this buttons data attribute
} else {
content.animate({height: "0px"});
$this.removeClass('on');
}
});
});
.content {
background: coral;
width: 100%;
height: 0px;
overflow:hidden;
}
.hiding{
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<button class="b" data-target="alpha" data-tall="4em">Button</button>
<button class="b" data-target="bravo" data-tall="7em">Button</button>
<button class="b" data-target="charlie" data-tall="5em">Button</button>
<div class="content">Le contenu</div>
<div class="hiding alpha"> some stuff </div>
<div class="hiding bravo"> other things </div>
<div class="hiding charlie"> bits and pieces </div>
i am trying to make a navigation bar for a webpage with sliding jquery panels. i want a small triangle under the button to appear when it is clicked and the arrow under the button corresponding with the previous page disapperas.
my HTML is:
<div id="navbar">
<div id="navbar_div">
<div class="navbar_container">
<ul id="nav" class="sf-menu">
<li class="bttn1 clicked" class="bttn1">Home<span class="subheading">Welcome to our page!</span></li>
<li class="bttn2 notclicked">About Us<span class="subheading">About the website and what it does</span></li>
</ul>
</div>
</div>
</div>
my css is:
#nav > li.clicked {
background: url(../images/menu-arrow.png) no-repeat center bottom;
}
my script is in the head of the page for button 2 click is:
function bttn2click () {
$("li.clicked").removeclass("clicked");
$("li.bttn2").addclass('clicked');
$("li.bttn2").removeclass("notclicked");
}
i don't know what i am meant to do. when i click buttons nothing happens (except for the links) i am aiming to change the class to match the clicked css class but it doesn't seem to work!
addClass and removeClass are case sensitive. jQuery does not have addclass or removeclass functions.
Use a jQuery event handler
<li class="bttn1 clicked" class="bttn1">Home<span class="subheading">Welcome to our page!</span></li>
then
jQuery(function () {
$('#nav li').click(function () {
$("#nav li.clicked").removeClass("clicked");
$(this).addClass('clicked').removeClass("notclicked");
})
})
Why yours is not working because the bttn2click is unaware about which li is clicked(along with the issues with method name)
Demo: Fiddle
I am using JS to show/hide divs via clicking on the side nav with jquery functions fadeIn() and fadeOut(). The problem I run into is as one div fades out, the next is fading in simultaneously. Also, if I click the link for the div that is already shown, it fades out and fades in again. I'm not sure if an IF statement would be the best approach to do two fixes:
1. Let shown div fully fadeOut before next starts to fadeIn.
2. Currently shown div will not fadeOut/In if same link is clicked.
Here is what I have thus far (without my broken attempt at an IF statement):
http://jsfiddle.net/k55Cw/1/
HTML:
<div class="container">
<header>
<ul class="sidenav">
<li><h2><a data-region="nav-1" href="#">About</a></h2></li>
<li><h2><a data-region="nav-2" href="#">Services</a></h2></li>
<li><h2><a data-region="nav-3" href="#">Team</a></h2></li>
<li><h2><a data-region="nav-4" href="#">News</a></h2></li>
<li><h2><a data-region="nav-5" href="#">Contact</a></h2></li>
</ul>
</header>
<div id="nav-1" class="infozone"><p>Hello I'm box 1.</p></div>
<div id="nav-2" class="infozone"><p>Hello I'm box 2.</p></div>
<div id="nav-3" class="infozone"><p>Hello I'm box 3.</p></div>
<div id="nav-4" class="infozone"><p>Hello I'm box 4.</p></div>
<div id="nav-5" class="infozone"><p>Hello I'm box 5.</p></div>
</div>
CSS:
.infozone{
float:left;
height:400px;
width:800px;
background-color: #000;
display:none;
}
JS:
$(document).ready(function() {
$('.sidenav a').click(function(){
$('.infozone').fadeOut(850);
var region = $(this).attr('data-region');
$('#' + region).fadeIn(850);
});
});
to chain the animations put the fadeIn inside the callback for fadeOut, and to cancel the function if it's currently shown, check if the div is already visible.
I've also had to add a check to see if the current .infozone div is visible - or else the fadeOut applies to hidden elements too, and the callback fires multiple times:
$(document).ready(function() {
$('.sidenav a').click(function(){
var region = $(this).attr('data-region');
var $region = $('#' + region);
if ($region.is(':visible')) return;
var $infozone = $('.infozone:visible');
if ($infozone.length === 0) {
$region.fadeIn(850);
} else {
$infozone.fadeOut(850, function() {
$region.fadeIn(850);
});
}
});
});
You could something like that:
html
This make you page works when javascript is disabled:
<header>
<ul class="sidenav">
<li><h2>About</h2></li>
<li><h2>Services</h2></li>
<li><h2>Team</h2></li>
<li><h2>News</h2></li>
<li><h2>Contact</h2></li>
</ul>
</header>
note that the href point to the id you want to show. This will works also for screen reader if you want to make your page accessible.
javascript. I have not tested it, you might have to fix few things, but the idea is there
$(document).ready(function() {
$('.sidenav a').click(function(e){
var href = $(this).attr('href');
// prevent default
e.preventDefault();
// prevent clicked twice
if(!$(this).hasClass('active'){
$('.sidenav a').removeClass('active');
$(this).addClass('active'){
$('.infozone').fadeOut(850);
$(href.substring(1)).fadeIn(850);
}
});
You should also consider adding some ARIA attributes and roles attributes.
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.