I have a image that is currently being styled with Jquery once it's clicked. I eventually hide it in Javascript. I want to reshow it, but I want it to have the border removed.
Here is HTML:
<div id="playOptionsWager" style="display: none">
<h4>Choose your move to beat the computer!</h4>
<img id="clickedRockWager" src="img/rock.jpg" onclick="playWagerRock()" />
<img id="clickedPaperWager" src="img/paper.jpg" onclick="playWagerPaper()"/>
<img id="clickedScissorsWager" src="img/scissors.jpg" onclick="playWagerScissors()" />
</div>
Jquery:
$(function () {
$("img").on("click",function() {
$(this).siblings().css('border','0px')
$(this).css('border', "solid 2px red");
});
});
Here is what I was trying in Javascript:
function autobet() {
coinBalance -= currentBet*2;
alert(getBalance());
document.getElementsByTagName("IMG").style.border="";
}
However when it reshows the div it has the border on it still.
Thanks for the help!
Your issue is that document.getElementsByTagName("IMG") returns a collection of elements, so simply applying .style.border on this collection won't work. Instead, you need to loop over this collection, and set every image within it to have no border using .style.border = 0;:
See working example (with div) below:
function removeBorder() {
[...document.getElementsByTagName("div")].forEach(elem => {
elem.style.border = 0;
});
}
.box {
height: 100px;
width: 100px;
background: black;
display: inline-block;
}
.active {
border: 3px solid red;
}
<div class="box"></div>
<div class="box active"></div>
<div class="box"></div>
<br />
<button onclick="removeBorder()">Remove border</button>
Also note that [...document.getElementsByTagName("IMG")] is a way of converting the collection of elements into an array of elements, which thus allows us to use the .forEach method to loop over it.
You started with jQuery, let's continue with jQuery.
function autobet() {
coinBalance -= currentBet*2;
alert(getBalance());
$("img").css("border","");
}
The problem is that getElementsByTagName() returns a collection not one element.
First you need to iterate over the collection of html elements you have - when using getElementsByTagName you get back an array of elements.
Second you need to give the elements a style of zero.
const divElements = document.getElementsByTagName("IMG");
for (let i=0; i < divElements.length; i++) {
divElements[i].style.border = 0;
}
You can see the code on stackbliz -
https://stackblitz.com/edit/border-issue?file=index.js
Related
If the "slick-initialized" div tag doesn't exist within a parent, then I want the parent ID (product recommender-recipe) to display none. Right now this is what I have set up:
HTML is set up like this:
<div id="product-recommender-recipe">
<div class="slick-initialized">
</div>
</div>
My JS so far. If length is 0, then have the parent ID display none. :
var productTemplate = document.getElementsByClassName("#product-recommender-recipe > .slick-initialized")
if (productTemplate.length === 0){
document.getElementById("product-recommender-recipe").style.display = "none";
}
Do I have this set up properly?
You can hide #product-recommender-recipe and check if .slick-initialized exists than show using just CSS.
it is working perfectly.
#product-recommender-recipe {
padding: 50px;
background-color: red;
display: none;
}
#product-recommender-recipe:has(.slick-initialized) {
display: block;
}
<!-- hidden if slick-initialized not exist -->
<div id="product-recommender-recipe">
<!-- <div class="slick-initialized"></div> -->
</div>
<br/>
<!-- visible if slick-initialized exist -->
<div id="product-recommender-recipe">
<div class="slick-initialized"></div>
</div>
You are pretty close. You have two mistakes in your implementation.
The first one is that you used getElementByClassName when in fact you are using an ID as your selector. Thus you should have used querySelector.
The second one is that you overused your selector. You have selected your parent div and placed it in a var so that you can reference it again.
Here is my implementation:
var productTemplate = document.querySelector("#product-recommender-recipe")
if (!productTemplate.querySelector('.slick-initialized')) {
productTemplate.style.display = none;
}
#product-recommender-recipe {
background: red;
width: 50px;
height: 50px;
}
<div id="product-recommender-recipe">
<div class="slick-initialized"></div>
</div>
getElementsByClassName expects a single class name – not a selector. If you want to use a selector, use querySelector or querySelectorAll. querySelector returns null if the element doesn't exists in the DOM.
const element = document.querySelector(".slick-initialized");
if(element === null) {
document.querySelector("#product-recommender-recipe").style.display = "none";
}
I'd like to create a product feature selection page where the user needs to select 3 features out of 6. Now, I got to a point where I can limit the number of selectable elements so if 3 elements are selected, the user wont be able to select a 4th one.
I need to modify this so when the user is attempting to select the 4th element, the 1st element they selected becomes unselected and the 4th element becomes selected. I hope it makes sense.
$('div').click(function(e) {
var $et = $(e.target);
if ($et.hasClass('fill')) {
$et.removeClass('fill');
} else {
if ($('.fill').length < 2) {
$et.addClass('fill');
}
}
});
div {
border: 1px solid blue;
height: 25px;
margin-bottom: 5px;
}
.fill {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<div id="1">one</div>
<div id="2">two</div>
<div id="3">three</div>
<div id="4">four</div>
This fiddle shows where I'm at with my code: http://jsfiddle.net/MarKP/32/
This fiddle is not mine, but this is exactly what I have right now in my project.
I'm trying to get this done using jQuery or plain JavaScript.
Thank you in advance!
To achieve this you can maintain an array which holds the order in which the elements were clicked. Then, when the limit is hit, you can remove the class from the element which was selected first. Try this:
var selections = [];
var $div = $('div').click(function(e) {
selections.push(this.id);
if (selections.length > 3)
selections.shift(); // remove first item
setState();
});
function setState() {
$div.removeClass('fill');
$div.filter(`#${selections.join(',#')}`).addClass('fill');
}
div {
border: 1px solid blue;
height: 25px;
margin-bottom: 5px;
}
.fill {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="1">one</div>
<div id="2">two</div>
<div id="3">three</div>
<div id="4">four</div>
<div id="5">five</div>
<div id="6">six</div>
Finally, note that jQuery 1.4.4 is massively outdated; nearly 10 years in fact. You need to update it.
I've created a template part in PHP that copies a button to each slide in a carousel using fullpage.js. The template part has a hidden div that should open up navigation for each slide. Trying the code below, I can only get this button to work on the first slide. I'm thinking an iterated class name might help, but not sure why querySelectorAll wouldn't do it. Any advice appreciated...
http://www.pulsecreative-clients.com/staging/hogshead/#golf
const clickOnMe = document.querySelectorAll(".course-button");
let clickOnMe = document.querySelectorAll(".course-button");
Array.from(clickOnMe).forEach(el => {
el.addEventListener("click", e => {
let showBox = e.currentTarget.nextElementSibling;
showBox.classList.toggle("open-nav");
});
});
.subnav-content {
position: fixed;
bottom: 15%;
z-index: 1;
box-sizing: border-box;
padding: 10px;
background-color: #000;
display: none;
}
.golfcoursebutton {
box-sizing: content-box;
min-width: 30px;
height: 30px;
padding: 4px;
margin: 4px;
background-color: #fff;
color: #000;
text-align: center;
}
.open-nav {
display: block;
}
<div id="jump-button" class="jumpbuttons-container">
<div class="subnav">
<button class="course-button">
JUMP TO <i class="fa fa-angle-up"></i>
</button>
<div class="subnav-content">
<div style="display: flex;">
<div class="golfcoursebutton">1</div>
<div class="golfcoursebutton">2</div>
<div class="golfcoursebutton">3</div>
<div class="golfcoursebutton">4</div>
<div class="golfcoursebutton">5</div>
<div class="golfcoursebutton">6</div>
</div>
<div style="display: flex;">
<div class="golfcoursebutton">7</div>
<div class="golfcoursebutton">8</div>
<div class="golfcoursebutton">9</div>
<div class="golfcoursebutton">10</div>
<div class="golfcoursebutton">11</div>
<div class="golfcoursebutton">12</div>
</div>
<div style="display: flex;">
<div class="golfcoursebutton">13</div>
<div class="golfcoursebutton">14</div>
<div class="golfcoursebutton">15</div>
<div class="golfcoursebutton">16</div>
<div class="golfcoursebutton">17</div>
<div class="golfcoursebutton">18</div>
</div>
</div>
</div>
</div>
EDIT
UPDATED WITH SOLUTION
querySelectorAll does not returns an array, so it doesn't have a forEach. Luckily, you can easily create an array out of it with Array.from:
// change this
clickOnMe.forEach(...
// to this
Array.from(clickOnMe).forEach(...
You're selecting the first of the document
document.querySelector(".subnav-content");
when it should be the first of the element
e.querySelector(".subnav-content");
I've created a template part in PHP that copies a button to each slide in a carousel using fullpage.js.
Unfortunately, your code re-use is throwing an error. If we look at your source, we see:
div.jump-button
button.course-button
div.subnav-content
<script>
const clickOnMe = ...
</script>
This is repeated ~20 times.
The issue is that const can only be declared once. After that, JS will throw an error. In fact, if we view the console, we see just that:
Basically, after the first declaration of const clickOnMe, an error is thrown after. That's why only the first one works. I would look into moving (and consolidating) the <script> where you define clickOnMe to the bottom and invoke that once all the HTML is loaded.
Edit:
Regarding your comment, I see what you're referring to. You're now querying all the elements correctly by moving the event binding to the bottom (awesome!), but your event listener will need to be updated as well. The change is actually answered here (by #jeyko-caicedo) by referring to the event object when toggling the classList.
A more complete answer would be that you need to reference the event object (to reference the clicked element) and then query the sibling subnav-content. One way is what jeyko suggested (via closure of the forEach). The other is in the event handler with either: 1 walking up the DOM tree (using e.currentTarget.parentNode) or 2: just reference the element directly like e.currentTarget.nextElementSibling.
let clickOnMe = document.querySelectorAll(".course-button");
Array.from(clickOnMe).forEach(function(el) { // updated `e` to `el`
el.addEventListener("click", (e) => {
let showBox = e.currentTarget.nextElementSibling;
showBox.classList.toggle("open-nav");
});
});
querySelectorAll returns a NodeList. It's essentially just an Array of DOM Nodes, but it doesn't support all of the Array methods that you'd expect it to have. You'll have to cast it to an array first, or manually for loop over it instead of using forEach.
I have an array, store, containing three images. I'm trying to display each image from this array in ascending order on each button click.
ie: first there should not be any image, on first click of the button the first image of the array should load on class level.
How can I achieve this?
function store()
{
var level=['https://via.placeholder.com/75x75?text=1','https://via.placeholder.com/75x75?text=2','https://via.placeholder.com/75x75?text=3'];
}
<div class="level" style=" width=100px; height:100px; border:2px solid #000;">
<img src="" id="levelimage" style=" width=100px; height:100px;"/>
</div>
<button onclick="store()">Click me</button>
I'm a bit confused of what you're asking but I think this will do the trick:
var i = 0;
function store() {
var level = ['https://via.placeholder.com/75x75text=1','https://via.placeholder.com/75x75?text=2','https://via.placeholder.com/75x75?text=3']
document.querySelector("img").src=level[i++];
if (i>level.length-1)i=0;
}
<div class="level" style=" width=100px; height:100px; border:2px solid #000;">
<img src="" id="levelimage" style=" width=100px; height:100px;"/>
</div>
<button onclick="store()">Click me</button>
Introduce a global variable i that will stay consistent no matter which function call was it and increase it by one every click, also use DOM to select your img tag and change it's src
var i=0;
function store() {
var level=['https://via.placeholder.com/75x75?text=1','https://via.placeholder.com/75x75?text=2','https://via.placeholder.com/75x75?text=3'];
document.querySelector(".level").firstChild.src=level[i];
i+=1;
}
// A named function, which expects two arguments:
// e: the Event Object, passed automatically from
// EventTarget.addEventListener();
// haystack: the array of images.
function imageProgress(e, haystack) {
// finding the relevant image by navigating the DOM:
// e.target gives the element that initiated the event,
// previousElementSibling finds the previous sibling that is
// an element, Element.querySelector() finds the first (if any)
// element that matches the supplied CSS selector:
let target = e.target.previousElementSibling.querySelector('img'),
// finding the current image:
currentImage = target.src,
// finding the index of the current image within the
// array of images (this returns -1 if the image
// is not found):
currentIndex = haystack.indexOf(currentImage);
// updating the src property of the <img> element;
// we first increment the currentIndex variable, and
// divide that updated index by the length of the Array.
// if there is no current image shown (or the src can't be
// found in the Array) we start at the first array-index;
// otherwise we increment through the Array:
target.src = haystack[++currentIndex % haystack.length];
}
let images = ['https://via.placeholder.com/75x75?text=1', 'https://via.placeholder.com/75x75?text=2', 'https://via.placeholder.com/75x75?text=3'],
// finding the <button> element:
button = document.querySelector('button');
// using unobtrusive JavaScript to bind the event-handler,
// using an arrow function:
button.addEventListener('click', (e) => {
imageProgress(e, images)
});
*,
::before,
::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.level {
width: 100px;
height: 100px;
border: 2px solid #000;
display: flex;
}
.level img {
margin: auto;
}
.level,
button {
margin: 1em;
}
<div class="level">
<img src="" id="levelimage" />
</div>
<button>Click me</button>
JS Fiddle demo.
References:
Arrow functions.
document.querySelector().
Element.querySelector().
EventTarget.addEventListener().
NonDocumentTypeChildNode.previousElementSibling.
I have a function that changes the src attribute of an icon when this one is clicked.
I also want it to hide the closest icon of the class fave_icon. I tried the following but it's not working:
function trash(event, trashcan){
event.stopPropagation();
if (trashcan.getAttribute('src') == "Iconos/tacho.png")
{
trashcan.src = "Iconos/warning.png"; //this works ok
var heart = trashcan.closest(".fave_icon");
heart.style.visibility = "hidden"
}
}
Basically I want to hide the closest element with class fave_icon to trashcan.
On the HTML I have this several times:
<button class="accordion">
<div>
<img src="Iconos/heart.png" onclick="fav(event,this);" alt="Fave" class="fave_icon">
</div>
<div>
<img src="Iconos/tacho.png" onclick="trash(event,this);" alt="Delete" class="delete_icon">
</div>
</button>
If fave_icon is a class then you have to place dot (.) before the class name as part of the selector.
Change var heart = trashcan.closest("fave_icon");
To
var heart = trashcan.closest(".fave_icon");
Based on the code and HTML you have provided you can do something like the following:
function trash(event, trashcan){
event.stopPropagation();
if (trashcan.getAttribute('src') == "Iconos/tacho.png"){
trashcan.src = "Iconos/warning.png"; //this works ok
var heart = trashcan.closest('button').querySelector('.fave_icon');
heart.style.visibility = "hidden";
}
}
<button class="accordion">
<div>
<img src="Iconos/heart.png" onclick="fav(event,this);" alt="Fave" class="fave_icon">
</div>
<div>
<img src="Iconos/tacho.png" onclick="trash(event,this);" alt="Delete" class="delete_icon">
</div>
</button>
From the trash icon, you go up a level to the div, select the previousElementSibling to get the heart's div, and then go down a level to the heart image itself.
Because the element is already included in the event target, you don't need to pass this. Or, even better, if you select the trash image first, you can avoid this entirely and use explicit variable names, which are easier to understand and debug.
But inline event handlers are essentially eval inside HTML markup - they're bad practice and result in poorly factored, hard-to-manage code. Seriously consider attaching your events with JavaScript, instead, eg: https://developer.mozilla.org/en/DOM/element.addEventListener
Another problem is that buttons should not have closing tags. Use a container element instead, like a div.
So, try something like this:
document.querySelectorAll('img[src="Iconos/tacho.png"]').forEach(img => {
img.onclick = () => {
const heartImg = img.parentElement.previousElementSibling.children[0];
heartImg.style.visibility = 'hidden';
};
});
<div class="accordion">
<div>
<img src="Iconos/heart.png" alt="Fave" class="fave_icon">
</div>
<div>
<img src="Iconos/tacho.png" alt="Delete" class="delete_icon">
</div>
</div>
you can add a class to the clicked element and use the general sibling combinator if the two items are adjacent.
document.getElementById("hide")
.addEventListener("click", (event) => {
event.target.classList.add('active');
}, false);
#hide.active~.element {
visibility: hidden;
}
#hide {
cursor: pointer;
}
.accordion {
padding: 15px;
background: lightgrey;
border-bottom: 1px solid grey;
}
.accordion div {
color: black;
margin-right: 20px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/icono/1.3.0/icono.min.css" rel="stylesheet" />
<div class="accordion">
<div class="icono-trash" id="hide"></div>
<div class="element icono-heart"></div>
</div>