I've got three elements with IDs "albums", "about", and "contact", and three links to show/hide them via the toggle() function, with IDs "togglealbums", "toggleabout", and "togglecontact". I only want one of these elements to be able to be seen at any time, so I wrote the following functions:
$('#togglealbums').click(function() {
if( $('#about').is(':visible') ) {
$('#about').toggle(function() {
$('#albums').toggle();
});
} else if( $('#contact').is(':visible') ) {
$('#contact').toggle(function() {
$('#albums').toggle();
});
} else {
$('#albums').toggle();
}
});
$('#toggleabout').click(function() {
if( $('#albums').is(':visible') ) {
$('#albums').toggle(function() {
$('#about').toggle();
});
} else if( $('#contact').is(':visible') ) {
$('#contact').toggle(function() {
$('#about').toggle();
});
} else {
$('#about').toggle();
}
});
$('#togglecontact').click(function() {
if( $('#albums').is(':visible') ) {
$('#albums').toggle(function() {
$('#contact').toggle();
});
} else if( $('#about').is(':visible') ) {
$('#about').toggle(function() {
$('#contact').toggle();
});
} else {
$('#contact').toggle();
}
});
First of all, if these are wildly inefficient or there is an easier way to do this, please let me know.
What I've found is that if none of the three DIVs is visible, clicking one of the toggle links will show/hide the respective div with no animation. However, if one of the DIVs is visible, clicking another toggle link will cause the div to shrink and fade and the new one expands and fades in, which I don't want (at least for now). This can be seen here: http://new.e17.paca.arvixe.com.
Can anyone tell me why this is happening?
Thanks!
EDIT:
Markup is here:
<body>
<div id="main">
<div id="nav">
<div id="menu">
<ul>
<li>Albums</li>
<li>About Me</li>
<li>Contact</li>
</ul>
</div>
</div>
<div id="albums">
Albums go here
</div>
<div id="about">
About info goes here
</div>
<div id="contact">
Contact info goes here
</div>
</div>
</body>
Your shrink-and-fade was happening because, if .toggle() is given a callback function, it assumes you want to animate the toggle instead of just switching it on/off. (According to the docs, as of this writing, that's only supposed to happen when you provide a duration. I've submitted a bug report about this.)
See http://jsfiddle.net/mblase75/byKeP/1/ for a reduced example of this. To solve it, just remove the callbacks and put the same code in the next line of your function.
As for streamlining your code, classes are your friends. HTML:
toggle albums
toggle about
toggle contact
<div class="toggleblock" id="albums">ALBUMS</div>
<div class="toggleblock" id="about">ABOUT</div>
<div class="toggleblock" id="contact">CONTACT</div>
Note the data- attributes, which jQuery will parse and make accessible through the .data() method. This makes it easy to store a unique div ID on the hyperlink itself, which in turn streamlines our JavaScript immensely. JS:
$('.togglelink').on('click',function(e) {
var id = $(this).data('block');
$('#'+id).toggle().siblings('.toggleblock').hide();
});
http://jsfiddle.net/mblase75/byKeP/
Related
I am attempting to show a certain div when the relative li is selected. If any other divs are showing, I need to hide that one and only display the new one. There 1000% is a way more efficient way to do this then creating many useStates.
import {useState} from 'react'
import './dope.css'
export const PageContent = () => {
const [one, setOne] = useState('false')
const [two, setTwo] = useState('false')
function toggle1(){
set1(!1)
}
function toggle2(){
set2(!2)
}
return (
<section>
<div className='middle_wrapper'>
<div className='left_menu_wrapper'>
<nav className='nav_black'>
<li><a href='#!' onClick={toggle1}>1</a></li>
<li><a href='#!' onClick={toggle2}>2</a></li>
<li><a href='#!'>3</a></li>
<li><a href='#!'>4</a></li>
<li><a href='#!'>5</a></li>
<li><a href='#!'>6</a></li>
<li><a href='#!'>7</a></li>
<li><a href='#!'>8</a></li>
<li><a href='#!'>9</a></li>
<li className='no_border'><a href='/'>10</a></li>
</nav>
</div>
<div className='right_content'>
<section className='full_page'>
<div id='new_res' className={one? 'inactive' : 'active'}>
<h1>This is a 1 test</h1>
</div>
<div id='all_res' className={two? 'inactive' : 'active'}>
<h1>This is a 2 test</h1>
</div>
</section>
</div>
</div>
</section>
)
}
---- From dope.css ----
.active {
display: block;
}
.inactive {
display: none;
}
--------
https://gyazo.com/1838ccf473832a00f341f4366b97b670
Like above, I would like to make this more efficient, it's probably something very simple that I am overlooking because I am tired and need sleep. I think I could simply just toggle the div's using href='#new_res' but how would I keep it hidden if it's not in use?
Any help would be appreciated, I know this is something simple and I by time someone answers, I may have found the solution. If not, thank you for helping!
If possible, it would be more efficient to simply use a checkbox.
However, if you have to use React state for flexibility, you could make a state with an array instead:
const [checkedArray, setCheckedArray] = useState([])
Whenever there is a new div to check toggle state, push a false into the array, when it is clicked, turn it to be true:
// Example
// Adding new state
setCheckedArray((current)=>[...current,false])
// Mutating 3rd item's state
setCheckedArray((current)=>{
const newArray = [...current];
newArray[3] = true;
return newArray
})
// Getting the info of the 3rd item of the array
const stateOfThirdItem = checkedArray[3]
Create a state to store all the components and their visibility flag. This will allow you to loop through them to dynamically render the anchors (and their onClick event) and also show them in the DOM.
https://codesandbox.io/s/so-71716290-bdsp9w?file=/src/PageContent.js
I'm quite new in coding, trying to educate myself because i'm interested. So, sorry if it's going to be a bit dumb question or not so specific or not really correct...
On my "practicing site" i'm having some navigation links, which are referring to different innerHTML contents (like different pages). I used the 'onClick' event to make them show up, for example like this:
<div class="nav" onClick="changeNavigation('a')">menu</div>
It works with texts perfectly, but my problem is that i don't know how to make the same with an image. So when i click on the image, i want to be redirected to that innerHTML page, like i did it with the text based button. I tried to do it like these two ways, but none of them worked.
<img src="picture.png" onClick="changeNavigation('a')" />
<div onClick="changeNavigation('a')"><img src="picture.png"></div>
Is it possible to make this with an image and the 'onClick' event? Or how else can i make this work?
By the way this is my script to make innerHTML show up:
<script>
function changeNavigation(id) {
document.getElementById('main').innerHTML = document.getElementById(id).innerHTML
}
</script>
I also tried to add my image an id that says 'main' like in the script this way, but with no result.
<img id="main" onClick="changeNavigation('f')" src="picture.png" />
Can you help me please? I would appreciate any answer, because i already searched about this and i didn't find anything that could've helped solve my problem and i'm really stuck right now.
(Sorry if my english isn't the best, it's not my native language.)
I have updated my answer to what you want. You need to the divs id you want to display as a parameter to the function you use for onclick. A sample is below.
var divs = ["Menu1", "Menu2", "Menu3", "Menu4"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
.main_div{text-align:center; background: #00C492; padding:20px; width: 400px;}
.inner_div{background: #fff; margin-top:20px; height: 100px;}
.buttons a{font-size: 16px;}
.buttons a:hover{cursor:pointer; font-size: 16px;}
img {cursor:pointer}
<div class="main_div">
<div class="buttons">
<img src="http://www.clker.com/cliparts/J/g/2/D/p/I/one-hi.png" width="50px" onclick="toggleVisibility('Menu1');"> <img src="http://www.clker.com/cliparts/E/x/J/x/m/z/blue-number-two-hi.png" width="50px" onclick="toggleVisibility('Menu2');">
<img src="http://www.clker.com/cliparts/L/H/T/b/g/N/three-md.png" width="50px" onclick="toggleVisibility('Menu3');">
<img src="http://www.clker.com/cliparts/v/G/G/A/D/s/four-md.png" width="50px" onclick="toggleVisibility('Menu4');">
</div>
<div class="inner_div">
<div id="Menu1">I'm container one</div>
<div id="Menu2" style="display: none;">I'm container two</div>
<div id="Menu3" style="display: none;">I'm container three</div>
<div id="Menu4" style="display: none;">I'm container four</div>
</div>
</div>
You can just keep all of the sections as children of #main, and selectively show them when the section button in clicked. E.g.,
HTML
<nav>
<button type="button" data-index=0>Show one</button>
<button type="button" data-index=1>Show two</button>
<button type="button" data-index=2>Show three</button>
</nav>
<main id="main">
<section>One</section>
<section class="hidden">Two</section>
<section class="hidden">Three</section>
</main>
CSS
.hidden {
display: none;
}
JavaScript
const buttons = Array.from(document.querySelectorAll('button'));
const contentBlocks = Array.from(document.querySelectorAll('section'));
function hideSections (arr) {
arr.forEach(a => {
a.classList.add('hidden');
});
}
function showSection (index, sections) {
// Just a basic check, not exhaustive by any stretch
if (index !== undefined && sections !== undefined) {
hideSections(sections);
sections[index].classList.remove('hidden');
}
}
buttons.forEach(button => {
button.addEventListener('click', () => {
const contentBlocks = Array.from(document.querySelectorAll('section'));
const index = button.getAttribute('data-index');
showSection(index, contentBlocks);
});
});
Obviously you'll have to adjust your selectors for your use case, but Here's a pen
Here's a GitHub Gist pointing to some examples I created on JSFiddle based off of your specific use case (Stack Overflow doesn't let me post links to JSFiddle directly without including code here, but it's easier to follow along/experiment entirely in JSFiddle):
https://gist.github.com/andresn/f100386f06ee28e35bd83c62d9219890
More advanced stuff:
Ideally, you'd use what's called event delegation instead of adding an onclick to every anchor (DRY = Don't Repeat Yourself is good to always keep in mind while programming and so is KISS = Keep It Simple Silly). Here is a resource explaining event delegation:
https://davidwalsh.name/event-delegate
You can even take this further by preloading all your images so they load behind the scenes when the user first loads the page:
https://perishablepress.com/3-ways-preload-images-css-javascript-ajax/
I am trying to make a simple educational game for kids, where they will drag and drop pictures of planets and need to put them in the correct boxes in the correct order.
What I'm trying to figure out is the JS needed to let check the element being dropped on a box is the one that will match that box. The code I have so far allows me to drag and drop but has no check. Here is what I have:
<script type="text/javascript">
function allowDrop(ev){
ev.preventDefault();
}
function drag(ev){
ev.dataTransfer.setData("content", ev.target.id);
}
function drop(ev){
ev.preventDefault();
var image= ev.dataTransfer.getData("content");
ev.target.appendChild(document.getElementById(image));
}
</script>
<section id="planetbox">
<img id="mercuryImg" draggable="true" ondragstart="drag(event)" src="./images/planets/mercury.gif">
</section>
<section id="mercurybox"ondrop="drop(event)" ondragover="allowDrop(event)"> </section>
Any help would be really great. P.S. needs to use HTML 5, CSS and JS only no libraries :)
I managed to solve my issue using the code below on the function drop(ev):
function drop(ev){
ev.preventDefault();
var image= ev.dataTransfer.getData("content");
if ( image == ev.target.id) {
ev.target.appendChild(document.getElementById(image));
}
else {
}
}
Im trying to setup so that when you hover over class .object1 -> in turn should reveal .obj_1 when you are not hovered on it, it should hide .obj_1. I may be a little off in my code, thanks for the help!.
$(document).ready(function() {
$(".obj_1 , .obj_2").hide();
});
$(".object1").hover(
function() { $(".obj_1").show(); },
function() { $(".obj_2").hide(); }
);
$(".object2").hover(
function() { $(".obj_2").show(); },
function() { $(".obj_1").hide(); }
);
Very simple it should be
$(document).ready(function() {
$(".obj_1 , .obj_2").hide();
});
$(".object1").hover(
function() { $(".obj_1").show(); },
function() { $(".obj_1").hide(); }
);
$(".object2").hover(
function() { $(".obj_2").show(); },
function() { $(".obj_2").hide(); }
);
The "hover" handler function signature is ( mouseInHandler, mouseOutHandler).
For object1 you want to show obj_1 on mouseIn, and hide it on mouseOut.
You don't need to reference obj_2 on object1 hover handlers.
Check out the fiddle I made here
FYI - the hover events act weird when you have complex inner content. ( for example, div within another div and so on ). I advise you to use "mouseenter" and "mouseleave"
UPDATING ANSWER AFTER REALIZING THIS IS A DROP DOWN MENU QUESTION
The drop down menu in CSS is a great example where "hover" won't suffice --> because the submenu disappears once you're not on the link anymore.. and that's not what we want.
It is important to note 3 things about drop down menus :
They can (?should?) be achieved purely with CSS
The HTML structure is important.
For example, consider the following structure instead :
<ul class="menu">
<li>
</li>
<li>
<ul class="menu">
<li>
</li>
</ul>
</li>
</ul>
This structure is recursive - you can have infinite levels of submenus - and the mouseenter/mouseleave on the "li" will hold since the submenu is part of the "li" item.
To see this in action have a look in my fiddle
Please also note that I removed the first "hide" from the onload code, and replaced it with css "display:none" - which resolves flickering on page load ( flickering means - first the submenu shows, and once the page loads, we hide it. )
A css solution would include a selector with "hover" on it ( yes, hover.. )
You can find plenty of blog posts about it while searching in google.
Here is the first one I found.
I'm struggling with this bit of code, and I'm not sure if it's even possible. I have a list of divs within a single parent element, and I need to collapse and expand certain sets. Here's an example:
<div id="parent">
<div class="alway_show">ALWAYS SHOW ME</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="alway_show">ALWAYS SHOW ME</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="collapse_me">COLLAPSIBLE</div>
<div class="collapse_me">COLLAPSIBLE</div>
</div>
So, in the initial state, .collapse_me will be display:none. There will be a link in always show to expand ONLY the collapsed divs below that particular .always_show div. I know this would be ten million times easier if the collapsible divs were in their own div, but I don't have control over the code. I have to make it work as is using jquery. Possible?
$('div.always_show').nextAll().each(function() {
if($(this).is('.collapse_me')) {
$(this).toggle();
}
else {
//this will halt the each "loop", stopping before the next .always_show
return false;
}
});
Of course you should not use my initial selector 'div.always_show', but rather supply it the actual element, which will be the parent of the clicked link. For example:
$('#expand_anchor').parent().parent().nextAll()...
var fncdiv = function(){
var el = this;
do{
el = $(el).next();
if ($(el).hasClass("collapse_me") )
$(el).toggle();
else
break;
}while (true)
};
$('#parent div.alway_show').bind("click", fncdiv);
You shouldn't need to use jQuery. It only requires some clever CSS:
#parent
{
/* normal parent css here */
}
#parent div
{
display: block;
}
#parent.collapsed
{
display: block;
}
#parent.collapsed div
{
display: none;
}
Selectors are applied in order of specificity. Since '#parent.collapsed div' is more specific than '#parent div', it should override. Now, all you need to do, is set the parent div's class, and you're done. You can use javascript to add/remove the 'collapsed' class to the DIV at runtime to toggle expansion without any additional effort:
// Mootools:
$('parent').addEvent('click', function()
{
$('parent').toggleClass('collapsed')
});