If I've got multiple items that I want to change from a display of 'none', to a display of 'block', what's the most efficient way of doing it?
The JS I would use for a single item is below, but I imagine there are several on a page or site. Should I make use of function constructors somehow?
var sideNav = document.getElementById('sideNav');
var menuButton = document.getElementById('menuButton');
function toggle() {
if(sideNav.style.display) {
sideNav.style.display = '';
} else {
sideNav.style.display = 'block';
}
}
menuButton.addEventListener('click', toggle);
Take a look, see if this helps you.
I did it with vanilla JS, I don't know if you are currently using jQuery (would be easier if yes)
What I did:
Every button have it's own id that is used to "connect" to the elements that it should toggle.
First I add the listener to all buttons, passing it's id when the function is called.
Then in the function, I used document.querySelectorAll to get all elements with the class that should be hidden/show.
Then finally I run a loop in those elements, showing or not showing, depending on it's current 'display'.
var menuButtons = document.querySelectorAll('.menuButton');
menuButtons.forEach(function(btn){
btn.addEventListener("click", toggle.bind(this, btn.id));
})
function toggle(id) {
var sideNav = document.querySelectorAll('.nav_' + id);
sideNav.forEach(function(el){
if (el.style.display == 'none'){
el.style.display = "block";
} else {
el.style.display = "none"
}
})
}
div{
height: 30px;
width: 50px;
margin: 2px 0;
background: #999;
text-align: center
}
<button id="menuButton1" class="menuButton">Toggle 1</button>
<button id="menuButton2" class="menuButton">Toggle 2</button>
<button id="menuButton3" class="menuButton">Toggle 3</button>
<div class="nav_menuButton1">1</div>
<div class="nav_menuButton1">1</div>
<div class="nav_menuButton2">2</div>
<div class="nav_menuButton3">3</div>
<div class="nav_menuButton3">3</div>
<div class="nav_menuButton3">3</div>
Probably there are better approaches, but I'm now in a hurry and this is the best I could think in that moment
Use JQuery to obtain it:
$(document).ready(function(){
$('#menuButton').click(toggle);
});
function toggle(){
$('.toggle-item').each(function(){
$(this).show();
})
}
and for all you items, add the toggle-item class with this css:
.toggle-item{
display: none;
}
If for every button there is an item to show, this is the way:
$(document).ready(function(){
$('.menuButton').each(function(){
var button = $(this);
button.click(function(){
toggle(button.attr('data-target')));
});
});
});
function toggle(itemId){
$(itemId).show();
}
Adding this attribute to button:
<button class="menuButton" data-target="#toggle-item-1"></button>
Related
This question was quite hard to summarize in the title, but what I have is a group of elements with the class panel. When I click a panel, I add a class of open to it. What I also want to do is remove the open class if another panel already has the open class.
Here is the code:
const panels = document.querySelectorAll('.panel');
function toggleOpen() {
this.classList.toggle('open');
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen));
Right now I can add the open class to however many panels I want, but I only want one panel to have the open class at a time.
Any help no how to achieve this?
The most efficient way is cache the DOM node is currently selected:
const panels = document.querySelectorAll('.panel');
let openedPanel = null;
function toggleOpen() {
if (openedPanel)
openedPanel.classList.remove('open');
this.classList.add('open');
openedPanel = this;
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen));
As was mentioned, it would be more efficient also delegate the event, so if all the panels share some ancestor, you should add the event listener to that ancestor, and then from the event listener doing something like:
toggleOpen({target}) {
const panel = target.closest('.panel')
if (openedPanel)
openedPanel.classList.remove('open');
panel.classList.add('open');
openedPanel = panel;
}
But as said they need to share a common ancestor.
Because you only want one opened at a time. You can directly target that element by getting the elements with class open, targeting the first element and removing class open before you add it to the selected one.
let opened = document.getElementsByClassName('open')[0];
if(opened!=undefined)
opened.classList.toggle('open');
This way you dont have to loop or save an extra global variable.
const panels = document.querySelectorAll('.panel');
function toggleOpen() {
let opened = document.getElementsByClassName('open')[0];
if(opened!=undefined)
opened.classList.toggle('open');
this.classList.toggle('open');
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen));
.panel {
width: 50px;
height: 50px;
margin: 1px;
background-color: aquamarine;
}
.open {
background-color: tomato;
}
<div class="panel"></div>
<div class="panel"></div>
<div class="panel"></div>
var doc = document;
var panelButtons = doc.querySelectorAll(".panel");
for (var i = 0; i < panelButtons.length; i++) {
panelButtons[i].addEventListener("click", function (evt) {
clearBlueFromButtons();
evt.target.classList.add("blue");
});
}
function clearBlueFromButtons(){
for (var i = 0; i < panelButtons.length; i++) {
panelButtons[i].classList.remove("blue");
}
}
.blue{
background: blue;
}
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
You can set the reference of the last opened panel in a variable and then remove the class name "open" when opening another panel, below an exemple:
// select all panels
const panels = document.querySelectorAll('.panel');
// define variable for the last clicked panel
let lastOpenedPanel;
/*
* Add the open class name for the current panel and remove it from the previous one
*/
function toggleOpen(
{
this.classList.toggle('open');
setLastOpenedTab(this);
}
/*
* Set the last opened tab and remove the open class from the previous one
*/
function setLastOpenedTab(context) {
if(lastOpenedPanel){
lastOpenedPanel.classList.remove('open');
}
lastOpenedPanel = context;
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen))
I recommend the use of javascript module pattern to better organize and share your functions
I recommend also the use of Jsdoc to better add documentation to your javascript code
Note that the property "classList" is not supported by IE9:
https://www.w3schools.com/howto/howto_js_toggle_class.asp
Try adding these lines BEFORE “this.classList.toggle” in your toggleOpen function:
for (var i = 0; i < panels.length; i++){
panels[i].classList.remove(“active”);
}
Use an if statement to check if the element has "open" and "panel" then remove the open class. Below is the pseudo code:
if ((element.classList.contains(open)) == True && (element.classList.contains(panel))){
element.classList.remove("open");
}
so this is my code:
let btnOne = $('.btn-one')
let btnTwo = $('.btn-twoo')
let btnThree = $('.btn-three')
I want to make some action when any of these buttons is clicked. How can I do that?
I've tried this
$(btnOne, btnTwo, btnThree).click(function (e) {
// Some action
})
But it didn't work.
How can I achieve this?
Thanks.
PS. I only want to achieve this with variables.
As the only option is to use the variables, you can combine them into an array and use .each to assign the event handler:
$([a,b,c]).each(function() { $(this).click(....
using the array with a .click directly doesn't work
var a = $(".a")
var b = $(".b")
var c = $(".c")
$([a,b,c]).each(function() { $(this).click(function() { alert($(this).text()); }) });
.a,.b,.c { border: 1px solid #ccc; width: 100px; height: 1.25em; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='a'>a</div>
<div class='b'>b</div>
<div class='c'>c</div>
Alternatively you can use .add to combine jquery collections (where each collection may only contain one element, it's still a collection), eg:
a.add(b).add(c).click(function() { ...
which uses chaining to add each additional variable
Using a variable and getting hold of all them through class:
<button id="btnOne" class="testButton">
One
</button>
<button id="btnTwo" class="testButton">
Two
</button>
<button id="btnThree" class="testButton">
Three
</button>
The script, simple enough:
let btnElement = $('.testButton');
$(btnElement).click(function (e) {
alert('Button Clicked');
})
Working JSFiddle: https://jsfiddle.net/e0Lj9b7t/
what you can do here is that you can use common class for every button and then you can detect which button was pressed.Check out the following HTML and jQuery.
$(".btn-one").click(function(e) {
var button_number = $(this).html();
alert(button_number + " pressed");
})
<button class="btn-one">btn-one </button>
<button class="btn-one"> btn-two </button>
<button class="btn-one"> btn-three</button>
"this" that us used inside the click function will detect which button was clicked.
-thanks
I want to click on an element to toggle a class being referenced on a completely unrelated element (not a child, parent or sibling)
For example, initially the code would look like this
<a id="button">Button</a>
<div class="navigation">
Foo
</div>
When the user clicks the element with the id button the HTML would change to look like this (the class "open" is referenced on element with "navigation" already referenced":
<a id="button">Button</a>
<div class="navigation open">
Foo
</div>
The user should be able to toggle the class by clicking the element with the id button.
I would like to use pure javascript to achieve this effect.
You could attach click event to the button with id button then on click select the element with class navigation using getElementsByClassName() (ti will return list of nodes) then select the first one using [0] then use toggle() :
document.getElementById('button').onclick = function(){
document.getElementsByClassName('navigation')[0].classList.toggle("open");
}
Hope this helps.
document.getElementById('button').onclick = function(){
document.getElementsByClassName('navigation')[0].classList.toggle("open");
}
.open{
background-color: green;
color: white;
}
<a id="button">Button</a>
<div class="navigation">
Foo
</div>
You don't really need javascript. Checkboxes work great at storing on/off state. You just need to get a little crafty with the CSS to use it elsewhere. Here is an example:
label.divcheck { color:blue; text-decoration:underline; }
input.divcheck { display:none; }
input.divcheck + div { display:none; }
input.divcheck:checked + div { display:block;}
<label class="divcheck" for="navigation">Button Nav</label>
<label class="divcheck" for="other">Button Other</label>
<input type="checkbox" class="divcheck" id="navigation"/>
<div class="navigation">
Foo
</div>
<input type="checkbox" class="divcheck" id="other"/>
<div class="navigation">
Other
</div>
Multiple elements with class navigation
navigation is a class, so I assume there is more than one element you would like to give class open on click on element with id button. Do it that way:
function toggleNavigation(element) {
element.classList.toggle('open');
}
document.getElementById('button').addEventListener('click', function() {
Array.from(document.getElementsByClassName('navigation')).forEach(toggleNavigation);
});
.navigation {
background-color: lightgreen;
}
.navigation.open {
background-color: lightblue;
}
<a id="button">Button</a>
<div class="navigation">Foo</div>
<div class="navigation">Foo</div>
<div class="navigation">Foo</div>
Single element with class or id navigation
If it is otherwise (i.e., there is only one element with class navigation, in which case it should be an id, not a class) you can replace above JavaScript to:
document.getElementById('button').addEventListener('click', function() {
document.getElementsByClassName('navigation')[0].classList.toggle('open');
});
or if you will change navigation to be an id:
document.getElementById('button').addEventListener('click', function() {
document.getElementById('navigation').classList.toggle('open');
});
You need to add event handlers. This can be done by simple setting the onClick property on the Element object:
document.getElementById('button').onClick = function onClick() {
document.getElementsByClassName('navigation')[0].className += 'open';
};
However, it's preferable that you use addEventListener so multiple event listeners can be added to the same element:
document.getElementById('button').addEventListener('click', function onClick() {
document.getElementsByClassName('navigation')[0].className += 'open';
}, false);
EDIT: It's also better to cache your element references in variables like so:
var button = document.getElementById('button');
var nav = document.getElementsByClassName('navigation')[0];
button.addEventListener('click', function onClick() {
nav.className += 'open';
}, false);
EDIT2: as in Zakaria's answer, you may want to use classList.add(x) instead of className += x. It's more in line with how jQuery's things work. However, be aware that classList is not supported in older versions of IE.
EDIT3: Here's a final version using classList.toggle
var button = document.getElementById('button');
var nav = document.getElementsByClassName('navigation')[0];
button.addEventListener('click', function onClick() {
nav.classList.toggle('open');
}, false);
And here's a quick replacement for classList using className instead:
function classList(elem) {
var cl = {
add: function (clas) {
elem.className += clas;
},
remove: function (clas) {
elem.className = elem.className.replace(clas, '');
},
toggle: function (clas) {
if (elem.className.indexOf(clas) > -1) {
cl.remove(clas);
} else {
cl.add(clas);
}
}
};
return cl;
}
// usage
classList(nav).add('open');
classList(nav).toggle('open');
Try this:
document.querySelector('div.navigation').classList.toggle('open');
This will work if you only have one div element that has the class navigation. It would be better to give it an id, for example id=navigation
I am trying to make webpage where there is a div in the center which is being changed, instead of going to different pages.
Ultimately, I would like to have the new div, when clicking on an arrow, to flow from right or left in to the center. But first I would like to make the divs appear and disappear when clicking on the arrows but unfortunately this doesn't work.
This is my javascript:
<script>
function changeToHome() {
document.getElementById("mainmain").style.display="block";
document.getElementById("mainmain2").style.display="none";
document.getElementById("mainmain3").style.display="none";
document.getElementById("mainmain4").style.display="none";
}
function changeToStudy() {
document.getElementById("mainmain").style.display="none";
document.getElementById("mainmain2").style.display="block";
document.getElementById("mainmain3").style.display="none";
document.getElementById("mainmain4").style.display="none";
}
function changeToJob() {
document.getElementById("mainmain").style.display="none";
document.getElementById("mainmain2").style.display="none";
document.getElementById("mainmain3").style.display="block";
document.getElementById("mainmain4").style.display="none";
}
function changeToContact() {
document.getElementById("mainmain").style.display="none";
document.getElementById("mainmain2").style.display="none";
document.getElementById("mainmain3").style.display="none";
document.getElementById("mainmain4").style.display="block";
}
function changePageRight() {
var displayValue5 = document.getElementById('mainmain').style.display;
var displayValue5 = document.getElementById('mainmain2').style.display;
var displayValue6 = document.getElementById('mainmain3').style.display;
var displayValue7 = document.getElementById('mainmain4').style.display;
if (document.getElementById('mainmain').style.display == "block") {
document.getElementById("mainmain").style.display="none";
document.getElementById("mainmain2").style.display="block";
}
else if (document.getElementById('mainmain2').style.display == "block") {
document.getElementById("mainmain2").style.display="none";
document.getElementById("mainmain3").style.display="block";
}
else if (document.getElementById('mainmain3').style.display == "block") {
document.getElementById("mainmain3").style.display="none";
document.getElementById("mainmain4").style.display="block";
}
else if (displayValue8 == block) {}
}
function changePageLeft() {
var displayValue = document.getElementById('mainmain').style.display;
var displayValue2 = document.getElementById('mainmain2').style.display;
var displayValue3 = document.getElementById('mainmain3').style.display;
var displayValue4 = document.getElementById('mainmain4').style.display;
if (displayValue == "block") { }
else if (displayValue2 == "block") {
document.getElementById("mainmain").style.display="block";
document.getElementById("mainmain2").style.display="none";
}
else if (displayValue3 == "block") {
document.getElementById("mainmain2").style.display="block";
document.getElementById("mainmain3").style.display="none";
}
else if (displayValue4 === "block") {
document.getElementById("mainmain3").style.display="block";
document.getElementById("mainmain4").style.display="none";
}
}
</script>
Now I have a few divs that look like this:
<div id="mainmain4">
<img style="width:400px;height:327px;margin-left:auto;margin-right:auto;display:block;" src="Untitled-22.png" />
<h2> My name </h2>
<p>Hi,</p>
<p>Some text</p>
</div>
With these css atributes:
#mainmain {
float: left;
width: 575px;
display: block;
position: relative;
}
And all other divs with display: none; so I can change this to block and the one that was block to none.
For some reason, after when I click on one button of the menu, which activates a changeToX() function, the arrows work great. But before that, when you first go to the website, it doesn't.
Can someone explain me what I do wrong?
You don't tell the browser which divs shall be displayed on load. You can use theonloadevent for this:
<body onload="changeToHome()">
One additional hint: you maybe don't want to use inline JavaScript and CSS.
jQuery is as this simple:
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
toggle!
<div id="mainmain">test text</div>
<script>
// you need this, only apply javascript when all html (dom) is loaded:
$(document).ready(function() {
$('.toggle-container').on('click', function(e) {
e.preventDefault(); // this prevents the real href to '#'
// .toggle() is like "on / off" switch for hiding and showing a container
$($(this).data('container')).toggle();
});
});
</script>
This function can be reused, because it is based on classes instead of id's.
Check this JSFiddle: http://jsfiddle.net/r8L6xg15/
Maybe this is of some use. I've tried to make a page control-like behaviour. You can select any container div and put elements in there that have the class 'page'. The JavaScript code will let you navigate those with buttons.
You can make it more fancy by adding the buttons through JavaScript. What you then have is basically a list of pages which are normally displayed as regular divs, but when the script kicks in, it changes them to a page control.
You can call this for any parent element, and in that sense it behaves a bit like a jQuery plugin. It is all native JavaScript, though. And not too much code, I hope. Like you said, I think it's good to learn JavaScript at first. It is very powerful by itself, and it's becoming increasingly powerful. jQuery adds a lot of convenience functions and provides fallbacks in case browser don't support certain features, or when implementations differ. But for many tasks, bare JavaScript will do just fine, and it certainly can't hurt to know your way around it.
Press the 'Run this snippet' button at the bottom to see it in action.
function Pages(element)
{
// Some initialization
var activePage;
// Find all pages within this element.
var pages = document.querySelectorAll('.page');
var maxPage = pages.length - 1;
// Function to toggle the active page.
var setPage = function(index)
{
activePage = index;
for (p = 0; p <= maxPage; p++)
{
if (p == activePage)
pages[p].className = 'page active';
else
pages[p].className = 'page inactive';
}
}
// Select the first page by default.
setPage(0);
// Handler for 'previous'
element.querySelector('.prev').onclick = function()
{
if (activePage == 0)
return;
setPage(activePage - 1);
}
// Handler for 'next'
element.querySelector('.next').onclick = function()
{
if (activePage == maxPage)
return;
setPage(activePage + 1);
}
// Add a class to the element itself. This way, you can already change CSS styling
// depending on whether this code is loaded or not. So in case of an error, the
// divs are just all show underneath each other, and the nav buttons are hidden.
element.className = element.className + ' js';
}
Pages(document.querySelector('.pages'));
.pages .page {
display: block;
padding: 40px;
border: 1px solid blue;
}
.pages .page.inactive {
display: none;
}
.pages .nav {
display: none;
}
.pages.js .nav {
display: inline-block;
}
<div class="pages">
<button class="nav prev">Last</button>
<button class="nav next">Next</button>
<div class="page">Page 1 - Introduction and other blah</div>
<div class="page">Page 2 - Who am I? Who are you? Who is Dr Who?</div>
<div class="page">Page 3 - Overview of our products
<ul><li>Foo</li><li>Bar</li><li>Bar Pro</li></ul>
</div>
<div class="page">Page 4 - FAQ</div>
<div class="page">Page 5 - Contact information</div>
</div>
To dos to make this a little more professional:
Add the navigation through JavaScript
Disable the buttons when first/last page has been reached
Support navigation by keys too (or even swipe!)
Some CSS transform (fade or moving) when toggling between pages
Smarter adding and removing of classes. Now I just set className, which sucks if someone would like to add classes themselves. jQuery has addClass and removeClass for this, which is helpful. there are also stand-alone libraries that help you with this.
Visible indication of pages, maybe with tabs at the top?
I'll get right to it:
What I need to do is hide a particular div with the press of a button, and it's supposed to be a toggle, so basically: Press once to hide, press again to show, press again to hide etc...
I want the hide/show rules to be done in CSS and the interaction in pure javascript (no jquery please). Well this is what I need to do, but I'm not quite sure how to execute the javascript code.
html:
<p class="button">Show/hide<p>
<div> I want to hide this by pressing the button above</div>
css:
#showhide {
display: none;
}
.button {
display: block;
height: 30px;
width: 100px;
background: green;
text-align: center;
padding-top: 10px;
padding-left: 0px;
font: 15px arial bold;
border: 1px solid black;
text-decoration: none;
list-style:none;
margin: 10px 0px 10px 0px;
}
http://jsfiddle.net/fyUJc/14/
Also, if you think this question doesn't belong here or is stupid, please try to refrain from being rude, I'm just trying to learn here.
You can make use an onclick method. Have your HTML as:
<p class="button" onclick="toggle_visibility('hideMe')">Show/hide</p>
<div id="hideMe">I want to hide this by pressing the button above</div>
And have the following JavaScript:
function toggle_visibility(id)
{
var e = document.getElementById(id);
if (e.style.display == 'block' || e.style.display=='')
{
e.style.display = 'none';
}
else
{
e.style.display = 'block';
}
}
DEMO
Here is an updated JSFiddle of your code that works with native browser methods and implement a simple toggle component - http://jsfiddle.net/fyUJc/31/
var button = document.querySelector('.button');
button.addEventListener('click', function(event) {
var target = document.querySelector(button.getAttribute('data-target'));
if (target.style.display == "none") {
target.style.display = "block";
button.innerHTML = button.getAttribute('data-shown-text');
} else {
target.style.display = "none";
button.innerHTML = button.getAttribute('data-hidden-text');
}
});
By creating a toggle button you are entering the field of GUI and this is something very complex.
Current browser technologies doesn't provide a rich set of tools to help you with everything you need to handle in GUIs. jQuery is of no help either, as GUIs are more about handling components and state than manipulating the DOM.
Even that the above code works in Chrome, you still need to take care of browser differences in both DOM and event and you will need a better abstraction for the components. There are quite a lot of problems that are not addressed in my code and that will be very difficult to address correctly if you write them from scratch every time. Things like:
How you initialize newly added togglers on the page ?
How you sync the state of the div and the button ?
How you extend and plug into the button behavior ?
I will strongly advise that you look into UI related libraries or frameworks that provide solutions for the common problems. See ReactJS, Dojo or Sencha (ex. ExtJS) to name a few. Look for frameworks that define a Widget/Component life-cycle and ways to extend and define custom ones.
Browser technologies just don't provide the proper abstractions for making UI components.
An alternative solution just using 'onclick' attribute inside your HTML tag:
<!DOCTYPE html>
<html>
<head>
<script>
function toggle(){
var div = document.getElementById("divSection");
if (div.style.display =='block'){
div.style.display = 'none';
return;
}
div.style.display ='block';
}
</script>
</head>
<body>
<p>Click the button to trigger a function.</p>
<p class="button" onclick="toggle()">Show/hide</p>
<div id='divSection'> I want to hide this by pressing the button above</div>
</body>
</html>
I hope it helps.
You can add attach an event listener to the P tag and have that call a Toggle() function to swap the display value as shown below.
Example here - JSFiddle
function Toggle() {
var div = document.getElementsByTagName('div')[0];
if (div.style.display == 'none') {
div.style.display = 'block';
} else {
div.style.display = 'none';
}
}
(function () {
var button = document.querySelectorAll(".button");
for (var i = 0; i < button.length; i++) {
if (button[i].addEventListener) {
button[i].addEventListener("click", function () {
Toggle();
});
} else {
button[i].attachEvent("click", function () {
Toggle();
});
}
}
})();
Though you would be better adding IDs to your elements to make them easier to reference.