Hello wizards of the internet!
Im new to javascript and finally found an efficient way to loop through ID's and toggle them. The code below adds the button id + "-box" text to show the result as 'display: flex'. If the ID is already visible it will set it to 'display: none'. For the future I need to add a lot of different smartphones to a website. I need an efficient way to only display 1 box at a time. I tried many different things but they all end in a huge document full of double code :(
(the style in html is to prevent the javascript double-click bug)
<!-- Smartphone Brands -->
<div id="brand-box" class="brand-container">
<button id="apple" class="brand" type="button" onclick="showBrand(this.id)">Apple</button>
<button id="samsung" class="brand" type="button" onclick="showBrand(this.id)">Samsung</button>
<button id="huawei" class="brand" type="button" onclick="showBrand(this.id)">Huawei</button>
</div>
<!-- Apple Smartphones -->
<div id="apple-box" class="block-container" style="display:none;">
<button id="apple1" class="block">iPhone 1</button>
<button id="apple2" class="block">iPhone 2</button>
<button id="apple3" class="block">iPhone 3</button>
</div>
<!-- Samsung Smartphones -->
<div id="samsung-box" class="block-container" style="display:none;">
<button id="samsung1" class="block">Samsung 1</button>
<button id="samsung2" class="block">Samsung 2</button>
<button id="samsung3" class="block">Samsung 3</button>
</div>
<!-- Huawei Smartphones -->
<div id="huawei-box" class="block-container" style="display:none;">
<button id="huawei1" class="block">Huawei 1</button>
<button id="huawei2" class="block">Huawei 2</button>
<button id="huawei3" class="block">Huawei 3</button>
</div>
function showBrand(clicked_id) {
var brand = document.getElementById(clicked_id+'-box');
if (brand.style.display == "none") {
brand.style.display = "flex";
}
else {
brand.style.display = "none";
}
}
One possible approach is modifying your function so that, when button is clicked, it...
memorizes the current visibility status of the target brand
hides all the brands
chooses a new value for the target brand depending on the old one
Like this:
function toggleBrand(clicked_id) {
var brand = document.getElementById(clicked_id+'-box');
var wasVisible = brand.style.display === 'flex';
var allBrands = document.querySelectorAll('[id$="-box"]');
allBrands.forEach(el => el.style.display = 'none');
brand.style.display = wasVisible ? 'none' : 'flex';
}
Now, while using attribute 'tail' selector is kinda neat, I'd recommend applying the same class or data attribute to all of those containers, and using according selector to collect them.
And yes, the renaming (showBrand => toggleBrand) was intentional: your original function actually toggles the brand, didn't show them. If you want instead to always show the brands on click, just drop that wasVisible check and always assign 'flex' as new value to brand.style.display.
Related
I have an rate app box,
I want the user to rate the app from 1-5 by clicking one of five buttons.
The button that was clicked should have color, all the others none. So if he clicked first on 3 and then 2, when clicking on 2 the color from the 3 button will be removed so only the last button was clicked (in this case 2) will have a color.
I DID manage to do it using button array, but i know for sure there is shorter way that isnt involved button array, only by code inside the function.
html:
<body>
<div class="container">
<div class="img-container">
<img src="./images/icon-star.svg" alt="" class="img-star">
</div>
<div class="content">
<h1>How did we do?</h1>
<p id="content-paragraph">
Please let us know how we did with your support request. All feedback is appreciated
to help us improve our offering!
</p>
</div>
<div class="buttons-container">
<button value = 1 class="choose " id="btn-one" onclick="paintBtn(this)">1</button>
<button value = 2 class="choose" id="btn-two" onclick="paintBtn(this)">2</button>
<button value = 3 class="choose" id="btn-three" onclick="paintBtn(this)">3</button>
<button value = 4 class="choose" id="btn-four" onclick="paintBtn(this)">4</button>
<button value = 5 class="choose" id="btn-five" onclick="paintBtn(this)">5</button>
</div>
<form action="thankYou.html">
<button id="submit">SUBMIT</button>
</form>
<script src="index.js"></script>
</body
js:
const buttonOne = document.getElementById("btn-one")
const buttonTwo = document.getElementById("btn-two")
const buttonThree = document.getElementById("btn-three")
const buttonFour = document.getElementById("btn-four")
const buttonFive = document.getElementById("btn-five")
const buttonsArr = [buttonOne, buttonTwo, buttonThree, buttonFour, buttonFive]
function paintBtn(button) {
buttonsArr.map(btn => btn.classList.remove("btn-clicked"))
button.classList.add("btn-clicked")
}
The shorter way of doing and not having to pass every button inside an array would be to do a document.querySelectorAll(".choose") and with that way you would be able to access the NodeList of matching elements to your class.
You can examine it just like any array. If the array is empty (that is, its length property is 0), then no matches would be found.
Otherwise, you can use standard array notation to access the contents of the list. You can use any common looping statement, such as a forEach statement.
It works just fine as in the attached example.
function paintBtn(newClickedButton) {
// clear styling from buttons
let buttons = document.querySelectorAll(".choose");
buttons.forEach(function(button){
button.classList.remove("btn-clicked");
});
newClickedButton.classList.add("btn-clicked");
}
.btn-clicked{
background-color: red;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<body>
<div class="container">
<div class="img-container">
<img src="./images/icon-star.svg" alt="" class="img-star">
</div>
<div class="content">
<h1>How did we do?</h1>
<p id="content-paragraph">
Please let us know how we did with your support request. All feedback is appreciated
to help us improve our offering!
</p>
</div>
<div class="buttons-container">
<button value = 1 class=" choose" id="btn-one" onclick="paintBtn(this)">1</button>
<button value = 2 class=" choose" id="btn-two" onclick="paintBtn(this)">2</button>
<button value = 3 class=" choose" id="btn-three" onclick="paintBtn(this)">3</button>
<button value = 4 class=" choose" id="btn-four" onclick="paintBtn(this)">4</button>
<button value = 5 class=" choose" id="btn-five" onclick="paintBtn(this)">5</button>
</div>
<form action="thankYou.html">
<button id="submit">SUBMIT</button>
</form>
<script src="index.js"></script>
</body>
use onclick functionallaity to solve this problem okay
You can use instead document.getElementsByClassName to search for the button that is currently clicked instead of searching and traversing through all of the buttons:
function paintBtn(newClickedButton) {
const clickedButtonClassName = "btn-clicked";
const clickedButton = document.getElementsByClassName(clickedButtonClassName)[0];
clickedButton.remove(clickedButtonClassName);
newClickedButton.classList.add(clickedButtonClassName);
}
I'm working on my real-estate project, I have a contact modal box and I want to get the title from tag a into the button value in modal box.
I'm not good at English, if I'm saying something wrong somewhere please forgive me
I have tried many ways but it still doesn't work and the result I get is the title but only works just for 1 id
function change() {
let a_id = document.getElementById('test');
let btn_id = document.getElementById("btn-test");
let btn = a_id.getAttributeNode('title').value;
// btn_id.value = btn;
btn_id.innerHTML = btn_id.value = btn;
}
<body>
<p>Click the button find out if the button has an onclick attribute specified.</p>
hello
<input type="button" onload="change()" title="hello" value="Try it" id="btn-test">
</body>
this is my code https://hastebin.com/ohasiqavun.xml?
You are supposed to use classes instead of ids here. Ids are unique and thus it only works for 1 element.
I just created the following alternative for you to get the values from every button seperate. noticed that I changed the HTML to 3 container who all include the same content. I removed the ID's and changed them for classes:
JS:
let changeallbuttons = document.querySelector('.changeallbuttons')
changeallbuttons.addEventListener('click', function() {
document.querySelectorAll('.container').forEach(item =>{
let button = item.querySelector('input')
let a = item.querySelector('.test')
button.value = a.getAttribute('title')
})
})
document.querySelectorAll('.container').forEach(item =>{
item.addEventListener('click', function() {
let button = item.querySelector('input')
let a = item.querySelector('.test')
button.value = a.getAttribute('title')
})
})
HTML:
<div class="container">
<p>Click the button find out if the button has an onclick attribute specified.</p>
<a href="#" title="bye1" class="test" >hello</a>
<input type="button" title="hello" value="Try it">
</div>
<div class="container">
<p>Click the button find out if the button has an onclick attribute specified.</p>
<a href="#" title="bye2" class="test" >hello</a>
<input type="button" title="hello" value="Try it">
</div>
<div class="container">
<p>Click the button find out if the button has an onclick attribute specified.</p>
hello
<input type="button" title="hello" value="Try it">
</div>
<input class="changeallbuttons" type="button" title="hello" value="Try it">
I need some help selecting the button in the example below. I am working with Wordpress and when I try to add a custom class to my button, it only adds it to the div that the button is in.
<div class="basic">
<button class="btn">Content</button>
</div>
Now I want to add some JS that changes the background color of the button when another button is clicked. When I select the div with the class assigned by me, the background color of the button doesn't change. I would have to select the button directly but I don't know how.
Any help is appreciated
There are several options to select the button:
querySelector
console.log(document.querySelector('.btn')); // Via its class name
console.log(document.querySelector('button')); // via its tag name
<div class="basic">
<button class="btn">Content</button>
</div>
querySelector returns the first matching element.
querySelectorAll returns all matching elements.
getElementsByClassName
console.log(document.getElementsByClassName('btn')[0]); // Select the first element, because getElementsByClassName returns a HTMLCollection!
<div class="basic">
<button class="btn">Content</button>
</div>
getElementsByTagName
console.log(document.getElementsByTagName('button')[0]); // Again select the first one!
<div class="basic">
<button class="btn">Content</button>
</div>
Now let's solve your problem:
// You can use either querySelector, getElementsByTagName, or getElementsByClassName. I decided for querySelector
function changeColor() {
document.querySelector('.btn').style.backgroundColor = "red";
}
<div class="basic">
<button class="btn">Content</button><button onclick="changeColor()">Change Color!</button>
</div>
Edit
If you want to select only the buttons whithin a specific div, you can do it this way:
function changeColor() {
var div = document.getElementsByClassName('basic')[0]; // Get the specific div
var buttons = div.getElementsByClassName('btn'); // Get the buttons by class, but only within the div
for (var i = 0; i < buttons.length; i++) { // Loop through the HTMLCollection and apply the CSS to every element
buttons[i].style.backgroundColor = "red";
}
}
<div class="basic">
<button class="btn">Content</button>
<button class="btn">Content</button>
<button class="btn">Content</button>
</div>
<button class="btn">I won't get selected</button>
<button onclick="changeColor()">Change color</button>
I have the following problem, I would like to create a few spoilers. This has worked so far, but I would like that if a spoiler is open and one clicks on another, the opened again closes.
<button title="Click to show/hide content" type="button" onclick="if(document.getElementById('spoiler') .style.display=='none') {document.getElementById('spoiler') .style.display=''}else{document.getElementById('spoiler') .style.display='none'}">Show/hide</button>
<div id="spoiler" style="display:none">
Content
</div>
<br><br>
<button title="Click to show/hide content" type="button" onclick="if(document.getElementById('spoiler2') .style.display=='none') {document.getElementById('spoiler2') .style.display=''}else{document.getElementById('spoiler2') .style.display='none'}">Show/hide</button>
<div id="spoiler2" style="display:none">
Content2
</div>
Assign a common class to all spoilers and on click hide the contents of all the spoilers using the class name and simply show only the one you want to show:
I have created a function for this like so:
<script>
function showSpoiler(spoilerId)
{
var spoilers = document.getElementsByClassName('spoilers');
for(var i=0;i<spoilers.length; i++)
{
spoilers[i].style.display = "none";
}
document.getElementById(spoilerId).style.display = "block";
}
</script>
<button title="Click to show/hide content" type="button" onclick="showSpoiler('spoiler');">Show/hide</button>
<div id="spoiler" class="spoilers" style="display:none">
Content
</div>
<br><br>
<button title="Click to show/hide content" type="button" onclick="showSpoiler('spoiler2');">Show/hide</button>
<div id="spoiler2" class="spoilers" style="display:none">
Content2
</div>
spoilers is the common class which needs to be hidden before showing the specific one.
Remember
getElementsByClassName() gives out an array that is why the for loop is in place.
To make it easier for you to start, I'll give you an example made for Event Listener for Radio buttons.
code:
document.getElementById("type_test").addEventListener("click", functio_test);
document.getElementById("type_test1").addEventListener("click", functio_test);
function functio_test(){
var x = document.querySelector('input[name="type_test"]:checked').value;
//var x = document.forms[0].elements.type_test.value;
if(x == "ola"){
alert("Ola José");
document.getElementById('disp_0').style.display = 'block';
document.getElementById('disp_1').style.display = 'none';
}
else if(x == "adeus"){
alert("Adeus José");
document.getElementById('disp_1').style.display = 'block';
document.getElementById('disp_0').style.display = 'none';
}
else {
alert("Continua José");
}
}
<div id="select_0">
<br> <input id = "type_test" type="radio" name="type_test" value="ola"> ola
<input id = "type_test1" type="radio" name="type_test" value="adeus"> adeus <br/> <br><br/>
</div>
<div id="disp_0" style="display:none">
<input type="text" name="lastname" value="ola Jose" ><br><br/>
</div>
<div id="disp_1" style="display:none">
<input type="text" name="lastname1" value="Adeus Jose" ><br><br/>
</div>
I hope the post helps you.
you can use classes to accomplish this (class="spoilers")
<button title="Click to show/hide content" type="button" onclick="toggleSpoiler('spoiler')"> Show/hide </button>
<div id="spoiler" style="display:none" class="spoilers">
Content
</div>
<br><br>
<button title="Click to show/hide content" type="button" onclick="toggleSpoiler('spoiler2')"> Show/hide </button>
<div id="spoiler2" style="display:none" class="spoilers">
Content2
</div>
<script>
function toggleSpoiler(id) {
var spoilers = document.getElementsByClassName("spoilers");
for(var i = 0; i < spoilers.length; i++) {
if (spoilers[i].id != id) {
spoilers[i].style.display = "none";
}
}
if(document.getElementById(id).style.display=='none') {
document.getElementById(id).style.display='';
} else {
document.getElementById(id).style.display='none';
}
}
</script>
The way I would do this would be to create two additional classes and add an additional div to use the parent/child association to determine which spoiler (in relation to the button) needs to be displayed.
Starting off with the classes, let's call them
.spoiler
and
.active
The idea is to make the .spoiler class hide and the .active class show, like so:
.spoiler {
display:none;
}
.spoiler.active {
display:block;
}
All spoiler elements would have .spoiler as a class and only the currently active spoiler would have the .active class, now let's create our new div which will bundle the spoilers and their buttons to have a common parent.
<div class="spoiler-item">
<button title="Click to show/hide content">
Show/Hide
</button>
<div class="spoiler">
Content
</div>
</div>
<div class="spoiler-item">
<button title="Click to show/hide content">
Show/Hide
</button>
<div class="spoiler">
Content2
</div>
</div>
Now we can use the relative "spoiler-item" class when a button is pressed to determine which spoiler is related to the button being pressed and also remove the "active" class from all other "spoiler" elements to make sure only one spoiler is shown at a time.
I recommend using jQuery for this, due to time constraints I'm not going to be able to do it in pure JS.
$(document).ready(function() {
$('.spoiler-item button').click(function(e) {
if($(this).parent('.spoiler-item').find('.spoiler').hasClass('active')) { // If the item we've selected is already active
$(this).parent('.spoiler-item').find('.spoiler').removeClass('active');
return;
}
$('.spoiler.active').removeClass('active'); // Close all open spoilers
$(this).parent('.spoiler-item').find('.spoiler').addClass('active'); // Open relative spoiler
});
});
See JSFiddle for working answer: https://jsfiddle.net/vvm4xe0m
In rendering out data within HTML, which prints out a div down the page, for every row found in the database, I'm trying to find a way to allow each button that sits in each div to toggle the individual example when clicked (with a default of display:none upon loading the page) - something such as:
function toggle_div(id) {
var divelement = document.getElementById(id);
if(divelement.style.display == 'none')
divelement.style.display = 'block';
else
divelement.style.display = 'none';
}
An example of the final markup :
<div>
<div class="wordtitle">Word</div>
<div class="numbers">1</div>
<div class="definition">Definition</div>
<button class="button" id="show_example" onClick="toggle_div('example')">Show example</button>
<div class="example" id="example">Example 1</div>
</div>
<div>
<div class="wordtitle">Word</div>
<div class="numbers">2</div>
<div class="definition">Definition</div>
<button class="button" id="show_example" onClick="toggle_div('example')">Show example</button>
<div class="example" id="example">Example 2</div>
</div>
getElementById() only toggles the first div's example, and getElementsByClass() hasn't seemed to work so far - not too sure how to do this - any ideas much appreciated!
First rule, do not insert multiple elements with the same ID. IDs are meant to be unique.
What you need is to toggle the example near the button you clicked, and not any (or all) .example to be showed / hidden. To achieve this, considering you used the [jquery] tag in your question, you can either use a selector to get the nearest .example of your button, or use jQuery's built-in functions to get it (.siblings()).
I would personally put the onclick out of your markup, and bind this custom function in your javascript.
Another important thing : if javascript is disabled client-side, the user won't ever see your example, as they are hidden by default in CSS. One fix would be to hide it initially with JS (see the snippet for this).
Here's a demonstration of what I mean :
$('.example-trigger').click(function() {
//Use the current button which triggered the event
$(this)
//Find the sibling you want to toggle, of a specified class
.siblings('.example-label')
//Toggle (hide or show) accordingly to the previous display status of the element
.toggle();
});
//Encouraged : hide examples only if Javascript is enabled
//$('.example-label').hide();
.example-label {
display: none;
/* Discouraged : if javascript is disabled, user won't see a thing */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div>
<button class="example-trigger">Toggle example 1</button>
<span class="example-label">Example 1</span>
</div>
<div>
<button class="example-trigger">Toggle example 2</button>
<span class="example-label">Example 2</span>
</div>
<div>
<button class="example-trigger">Toggle example 3</button>
<span class="example-label">Example 3</span>
</div>
As #Sean stated, you need the ID to be unique since that's the way you are getting your elements.
$words .= '<div class="wordtitle">' . $word .'</div>
<div class="numbers">' . $i . '</div>
<div class="definition">' . $definition . '</div>
<button class="button" id="show_example" onClick="toggle_div(\'example\''.$i.')">
show example</button>
<div class="example" id="example'.$i.'">' . $example . '</div>
<br/><br/>';
$i++;
#show_example will also be repeating so you will probably want to change that to a class.
Another answer, only because I had the answer ready and was called away before I could post it. So here it is.
Notice that for repeating elements, classes are used instead of IDs. They work just as well, and (as everyone else has already said), IDs must be unique.
jsFiddle demo
HTML:
<div class="def">
<div class="wordtitle">Aardvark</div>
<div class="numbers">1</div>
<div class="definition">Anteater</div>
<button class="button show_example">show example</button>
<div class="example" id="example">The aardvark pushed its lenghty snout into the anthill and used its long, sticky tongue to extract a few ants.</div>
</div>
<div class="def">
<div class="wordtitle">Anecdote</div>
<div class="numbers">2</div>
<div class="definition">Amusing Story</div>
<button class="button show_example">show example</button>
<div class="example" id="example">The man told an anecdote that left everyone laughing.</div>
</div>
jQuery:
var $this;
$('.show_example').click(function() {
$this = $(this);
if ( $this.hasClass('revealed') ){
$('.example').slideUp();
$('.show_example').removeClass('revealed');
}else{
$('.example').slideUp();
$('.show_example').removeClass('revealed');
$this.parent().find('.example').slideDown();
$this.addClass('revealed');
}
});