How to stop children from triggering parent mouseenter event - javascript

My buttons have one image inside them, and the mouseenter event gets triggered by both the button AND the image. I would like the event to be triggered only once by "hovering" the BUTTON, not the image.
HTML, the only relevant part of the code are the buttons and their IDs.
<div class="catalogue-hidden">
<div id="product-1" class="product estusFlask">
<img src="./products/Item_Estus_Flask.png" />
<span>Estus Flask</span>
<button id="btn-1" class="button">
1000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-2" class="product">
<img src="./products/Mask_of_the_Father.png" />
<span>Mask of the Father</span>
<button id="btn-2" class="button">
8000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-3" class="product">
<img src="./products/Giant_Armor.png" />
<span>Giant Armor</span>
<button id="btn-3" class="button">
5000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-4" class="product">
<img src="./products/Giant_Gauntlets.png" />
<span>Giant Gauntlets</span>
<button id="btn-4" class="button">
5000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-5" class="product">
<img src="./products/Giant_Leggings.png" />
<span>Giant Leggings</span>
<button id="btn-5" class="button">
5000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-6" class="product">
<img src="./products/Wpn_Zweihander.png" />
<span>Zweihander</span>
<button id="btn-6" class="button">
3500
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-7" class="product">
<img src="./products/Grass_crest_shield.png" />
<span>Grass Crest Shield</span>
<button id="btn-7" class="button">
1500
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-8" class="product">
<img src="./products/Havel's_Ring.png" />
<span>Havel's Ring</span>
<button id="btn-8" class="button">
2000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-9" class="product">
<img src="./products/Ring_of_Favor_and_Protection.png" />
<span class="fap">Ring of Favor and Protection</span>
<button id="btn-9" class="button">
2000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-10" class="product">
<img src="./products/Pyro_Pyromancy_Flame.png" />
<span>Pyromancy Flame</span>
<button id="btn-10" class="button">
1000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div id="product-11" class="product">
<img src="./products/Black_Flame.png" />
<span>Black Flame</span>
<button id="btn-11" class="button">
5000
<img src="./icons/soul_of_a_proud_paladin.png" />
</button>
</div>
<div onclick="stopBgm(); changeVideo(); hideHud()" id="product-12" class="product-hidden">
<img src="./products/7011.png" />
<span>Well, what is it?</span>
<button id="btn-12" class="button-hidden">
PWN SOME NOOBZ
</div>
JavaScript
function selectSfx() {
var audio = document.querySelector(".selectSfx");
audio.currentTime = 0;
audio.play();
}
for (let idNumber = 1; idNumber < 13; idNumber++) {
setTimeout(() => {
document
.getElementById(`btn-${idNumber}`)
.addEventListener("mouseenter", selectSfx, true);
document
.getElementById(`btn-${idNumber}`)
.addEventListener("click", (e) => {
condition++;
console.log(condition);
okSfx();
document.getElementById(`product-${idNumber}`).className =
"product-fake";
document.getElementById(`btn-${idNumber}`).disabled = true;
document
.getElementById(`btn-${idNumber}`)
.removeEventListener("mouseenter", selectSfx, true);
if (condition >= 11) {
document.querySelector(".product-hidden").className = "product";
document.getElementById("btn-12").className = "button";
}
});
}, 4000);
}
When I add the mouseenter event like this, the SelectSfx(); does NOT play when I hover the images within the buttons. The sound plays only once, which is the desired result. But unfortunately I am unable to disable the event once the button gets disabled.
function selectSfx() {
var audio = document.querySelector(".selectSfx");
audio.currentTime = 0;
audio.play();
}
for (let idNumber = 1; idNumber < 14; idNumber++) {
setTimeout(() => {
document
.getElementById(`btn-${idNumber}`)
.addEventListener("mouseenter", (e) => {
selectSfx();
});
}, 4000);
}

Add the following code just below your "setTimeout" line in your javascript file:
document
.getElementById(`btn-${idNumber}`)
.querySelectorAll('img')
.forEach((img) => {
img.style.pointerEvents = 'none';
});
The code removes pointer events from images that are within the desired buttons.
Edit:
Perhaps, the "more correct" answer is to remove the third argument of the 'addEventListener' function call:
ORIGINAL:
document
.getElementById(`btn-${idNumber}`)
.addEventListener('mouseenter', selectSfx, true);
FIXED:
document
.getElementById(`btn-${idNumber}`)
.addEventListener('mouseenter', selectSfx);
When useCapture is set to true, the event listener is triggered during the capturing phase of the event propagation process. This means that the event is first captured by the outermost element and then propagated to the inner elements.
When useCapture is set to false or not specified, the event listener is triggered during the bubbling phase of the event propagation process. This means that the event is first captured by the innermost element and then propagated to the outer elements.

You can ignore pointer events on the image using CSS and that way the pointer will only interact with the button.
<style>
.button img {
pointer-events: none;
}
</style>

Just use the Element: mouseover event with CSS pointer-events: none.
The mouseover event is fired at an Element when a pointing device
(such as a mouse or trackpad) is used to move the cursor onto the
element or one of its child elements.
let button = document.querySelector("button");
document.querySelector("button > img").style.pointerEvents = 'none';
button.addEventListener("mouseover", function (e) {
console.log(e.target.tagName);
}, false);
<div id="product-1" class="product estusFlask">
<button id="btn-1" class="button">
1000
<img src="https://www.aexp-static.com/cdaas/one/statics/axp-static-assets/1.8.0/package/dist/img/logos/dls-logo-bluebox-solid.svg" />
</button>
</div>

Related

Problems with toggling more than one Image when clicking

I have my code set so that an image can change after clicking the image. I understand getElementById is meant to get results from one class name, but I don't know how to expand on that, and have the same result without changing the class name. I tried querySelector, but I think I am missing something. Any help would be appreciated. Here is my code:
<!--how do I make this apply to all images?-->
function changeImage() {
let displayImage = document.querySelector('#img-area, #star-picture, #colorful')
if (displayImage.src.match('Kabuto.jpg')) {
displayImage.src = 'PersonalCreations/LylatForce.jpg'
} else {
displayImage.src = 'Kabuto.jpg'
}
}
<!--image area or main img-->
<div class="row">
<div class="column">
<img id="img-area" src='Kabuto.jpg' class="responsive" alt="" onclick="changeImage()" height="200" with="200">
<button class="first" onclick="document.getElementById('img-area').src='PersonalCreations/LylatForce.jpg'">Change Image</button>
</div>
<div class="column">
<img id="star-picture" src="Kabuto.jpg" height="200" with="200" />
<button onclick="document.getElementById('star-
picture').src='PersonalCreations/Year6969.jpg'">Change Image</button>
</div>
<div class="column">
<img id="colorful" src="Kabuto.jpg" height="200" with="500" />
<button onclick="document.getElementById('colorful').src='PersonalCreations/BallInTheShoeProductions.jpg'">Change Image</button>
</div>
<div class="column">
<img id="holiday" src='Kabuto.jpg' alt="" onclick="changeImage()" height="200" with="200">
<button onclick="document.getElementById('holiday').src='PersonalCreations/ChristmasFestivalProject.jpg'">Change Image</button>
</div>
</div>
<p>Hello World</p>
<script src="imgchanger.js"></script>
First, CSS styling and JavaScript should not be used inline with HTML. You should separate out those things.
Your issue is that you have:
let displayImage = document.querySelector ('#img-area, #star-picture, #colorful')
But, .querySelector() will only return the first matching element. You need .querySelectorAll(), which will return a collection of all matching elements.
Or, you can avoid all of that and do this:
// Set up a single event handler for all clicks in the document
document.addEventListener("click", function(evt){
// But test to see if the click originated at a button
if(evt.target.nodeName === "BUTTON"){
// Get the button's parent div and then the source of the first img within that
let img = evt.target.closest("div").querySelector("img").src;
// Find out which button was clicked by looking at its class
switch (evt.target.className){
case "first":
// Change the source
img = "PersonalCreations/LylatForce.jpg";
break;
case "second":
img = "PersonalCreations/Year6969.jpg";
break;
case "third":
img = "PersonalCreations/BallInTheShoeProductions.jpg";
break;
case "fourth":
img = "PersonalCreations/ChristmasFestivalProject.jpg";
break;
}
console.clear();
console.log("Image source is now: " + img);
}
});;
.img200x200 { height:200px; width:200px; }
.img200x500 { height:200px; width:500px; }
<!-- See how much cleaner the HTML is now that the CSS and
JavaScript have been separated out? -->
<div class="row">
<div class="column">
<img src="Kabuto.jpg" class="responsive img200x200" alt="">
<button class="first">Change Image</button>
</div>
<div class="column">
<img src="Kabuto.jpg" class="responsive img200x200" alt="">
<button class="second">Change Image</button>
</div>
<div class="column">
<img src="Kabuto.jpg" class="responsive img200x500" alt="">
<button class="third">Change Image</button>
</div>
<div class="column">
<img src="Kabuto.jpg" class="responsive img200x200" alt="">
<button class="fourth">Change Image</button>
</div>
</div>
<p>Hello World</p>

How to change a dynamic button text

Created 3 dynamic divs(sea_p,sea_p_div,div_btns), inside the third(div_btns) created 2 buttons
how can i change the text inside these dynamic buttons before adding to body?
let div = $(`<div class="Search_div"></div>`)
let p = $(`
<div class="sea_p">
<div class="sea_p_div">
<div class="p_img">
<img src="" alt="" width="80" />
<div class="div_span">
<span class="p_name"></span>
<span class="p_surname"></span>
</div>
</div>
<div class="div_btns">
<button class="req_btn req_check1" data-id="">Text1</button>
<button class="req_btn req_check2" data-id="">Text2</button>
</div>
</div>
</div>`)
div.append(p)
//change text here
$('body').append(div)
let div = $(`<div class="Search_div"></div>`)
let p = $(`
<div class="sea_p">
<div class="sea_p_div">
<div class="p_img">
<img src="" alt="" width="80" />
<div class="div_span">
<span class="p_name"></span>
<span class="p_surname"></span>
</div>
</div>
<div class="div_btns">
<button class="req_btn req_check1" data-id="">Text1</button>
<button class="req_btn req_check2" data-id="">Text2</button>
</div>
</div>
</div>`)
div.append(p)
//change text here
p.find(".req_check1").html('New Text');
p.find(".req_check2").html('New Text 2');
$('body').append(div)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
Please try this.
window.onload = function() {
$(".req_check1").html('New Text');
$(".req_check2").html('New Text 2');
}
Thank you.
You can use text() method of jQuery, on the jQuery object of button whose text you want to change.
NOTE : Use it just after appending the p tag to the body.
var buttonWrap = $('.sea_p .div_btns button');
buttonWrap.eq(0).text("Text for button 1");
buttonWrap.eq(1).text("Text for button 2");

Simple Javascript code (function) is not working

The simple javascript is not working. When I test the code in live preview (chrome), it says "ThfJ8q9:58 Uncaught ReferenceError: textpage is not defined
at HTMLButtonElement.onclick (ThfJ8q9:58)"
What I am trying to do is to change the background image of the div "chat" when the button is clicked to the new image specified.
HTML:
<div id="chat">
<div class="button-class">
<button type="button" onclick="textpage()"> <img class= "submit-button-
img" alt="submit-button" src="images/text.button.png"> </button>
</div>
</div>
JAVASCRIPT DOCUMENT:
function textpage() {
document.getElementById("chat").style.backgroundImage = "url('full-convesation-
MRP.png')";
}
Could use something like this to listen for a click on the button
https://codepen.io/CTBroon/pen/RwbRGQq
HTML
<div id="chat">
<div class="button-class">
<button type="button" id="btns"> <img class= "submit-button-
img" alt="submit-button" src="images/text.button.png"> </button>
</div>
</div>
JS
var btntrigger = document.getElementById('btns');
btntrigger.addEventListener('click', function(){
document.getElementById("chat").style.backgroundImage = "url('https://placehold.it/400x400')";
})
Or have a closer look at your syntax on the orginal, fixed here:
https://codepen.io/CTBroon/pen/RwbRGQq
HTML
<div id="chat">
<div class="button-class">
<button type="button" onclick="textpage()">
<img class="submit-button-img" alt="submit-button" src="images/text.button.png"> </button>
</div>
</div>
JS
function textpage() {
document.getElementById("chat").style.backgroundImage = "url('https://placehold.it/400x400')";
}
:)

Accessing multiple elements by getElementsByClassName() with JS

I am trying to create multiple popups on one page that would appear after clicking a button corresponding to them. I currently have them under the same class, as in here:
<div>
<!-- Popup -->
<div class="popup">
<div class="popup-content">
Some text here
</div>
</div>
<!-- Button -->
<img src="button.png" class="popup-button"/>
</div>
The problem is that I am struggling to access individual elements with my javascript code. I am not sure what to replace the manual array accessing ( [0] right now ) with.
<script>
// Get the popup
var popup = document.getElementsByClassName("popup")[0];
// Get the button that opens the popup
var btn = document.getElementsByClassName("popup-button")[0];
// When the user clicks the button, open the popup (hidden by default)
btn.onclick = function() {
popup.style.display = "block";
}
</script>
Now, I could create multiple scripts and access the arrays manually for each element but of course I am trying to automate it, so that script would run depending on which button was clicked. Say, if 5th button was clicked, 5th popup appears. Thank you!
Best way to link multiple elements in Javascript is using an id through the dataset of the elements.
// Get the popup's btn list
var popupsBtn = document.getElementsByClassName("popup-btn");
// Go through the popup's btn list
for (var i = 0; i < popupsBtn.length; i++) {
// Define the onclick event on popup's btn
popupsBtn[i].onclick = function() {
// Get the popup associated to the btn with the data-popup-id
var popup = document.getElementById("popup-" + this.dataset.popupId);
// Use a class to toggle popup visible or not
popup.classList.toggle("visible");
}
}
.popup {
display: none;
}
.popup.visible {
display: block;
}
<!DOCUMENT html>
<html>
<head></head>
<body>
<div>
<div id="popup-1" class="popup">popup 1 here</div>
<img src="button.png" class="popup-btn" data-popup-id="1" />
</div>
<div>
<div id="popup-2" class="popup">popup 2 here</div>
<img src="button.png" class="popup-btn" data-popup-id="2" />
</div>
<div>
<div id="popup-3" class="popup">popup 3 here</div>
<img src="button.png" class="popup-btn" data-popup-id="3" />
</div>
</body>
</html>
Given your HTML, it would probably be easiest to just access the previous sibling of the clicked button to get to the .popup, and then change its style:
document.querySelectorAll('.popup-button').forEach(button => {
button.onclick = () => {
button.previousElementSibling.style.display = 'block';
};
});
.popup {
display: none;
}
<div>
<div class="popup">
<div class="popup-content">
Some text here1
</div>
</div>
<img src="button.png" class="popup-button" />
</div>
<div>
<div class="popup">
<div class="popup-content">
Some text here2
</div>
</div>
<img src="button.png" class="popup-button" />
</div>
<div>
<div class="popup">
<div class="popup-content">
Some text here3
</div>
</div>
<img src="button.png" class="popup-button" />
</div>
You can use other attributes to identify the button. You could not rely on the className alone.
You can use data-id attribute and pass it in the method. using this.
Depending on your HTML structure, there are multiple possibilities.
Anyway, I suggest you to use .querySelectorAll() to get your elements, and then use a .forEach() to execute your code.
I tried to use much of your code to make it work correctly.
With a parent div
// Get all the buttons that opens the popups
var btns = document.querySelectorAll(".popup-button");
btns.forEach(function(btn, index) {
// When the user clicks the button, open the popup that is in the same parent div
btn.onclick = function() {
btn.closest('div').querySelector('.popup').style.display = "block";
}
});
.popup {
display: none;
}
<div>
<div class="popup">
<div class="popup-content">Pop-up 1</div>
</div>
<img src="button.png" class="popup-button" />1
</div>
<div>
<div class="popup">
<div class="popup-content">Pop-up 2</div>
</div>
<img src="button.png" class="popup-button" />2
</div>
<div>
<div class="popup">
<div class="popup-content">Pop-up 3</div>
</div>
<img src="button.png" class="popup-button" />3
</div>
Without a parent div
// Get the popups
var popups = document.querySelectorAll(".popup");
// Get the buttons that opens the popups
var btns = document.querySelectorAll(".popup-button");
btns.forEach(function(btn, index) {
// When the user clicks the button, open the popup (hidden by default)
btn.onclick = function() {
popups[index].style.display = "block";
}
});
.popup {
display: none;
}
<div class="popup">
<div class="popup-content">Pop-up 1</div>
</div>
<img src="button.png" class="popup-button" />
<br>
<br>
<div class="popup">
<div class="popup-content">Pop-up 2</div>
</div>
<img src="button.png" class="popup-button" />
<br>
<br>
<div class="popup">
<div class="popup-content">Pop-up 3</div>
</div>
<img src="button.png" class="popup-button" />
This solution withour parent div will work even if the popups and the buttons are not next to each other. But the order (and index) of the elements need to be the same. See it here:
// Get the popups
var popups = document.querySelectorAll(".popup");
// Get the buttons that opens the popups
var btns = document.querySelectorAll(".popup-button");
btns.forEach(function(btn, index) {
// When the user clicks the button, open the popup (hidden by default)
btn.onclick = function() {
popups[index].style.display = "block";
}
});
.popup {
display: none;
}
<img src="button.png" class="popup-button" />1
<img src="button.png" class="popup-button" />2
<img src="button.png" class="popup-button" />3
<div class="popup">
<div class="popup-content">Pop-up 1</div>
</div>
<div class="popup">
<div class="popup-content">Pop-up 2</div>
</div>
<div class="popup">
<div class="popup-content">Pop-up 3</div>
</div>
Hope it helps.

MVC View is being refreshed after button onclick

I have a View and it's Controller. The view has the following button (which is repeated multiple times for different variants):
<button type="button" id="#variant.id" onclick="return Select()" style="padding:10px 15px;width:100%;height:100%;margin-top:-10px;">
<div class="col-md-4">
<img width="100" height="100" style="padding:5px" src="/test/#variant.logo" title="#variant.name" />
</div>
<div class="col-md-8">
<h4>#variant.name</h4>
</div>
</button>
This is the function that it accesses:
<script type="text/javascript">
function Select()
{
alert("test");
return false;
}
</script>
For some reason after the function call, the View is always being refreshed. Do you know what might be wrong with my code?
You should maybe use prevent default to stop the event, see also event.stopPropagation().
Here I'm preventing the event, maybe you should use it if your condition is false.
function select(e){
e.preventDefault();
alert('test');
return false;
}
<button type="button" id="#variant.id" onclick="select(event)" style="padding:10px 15px;width:100%;height:100%;margin-top:-10px;">
<div class="col-md-4">
<img width="100" height="100" style="padding:5px" src="/test/#variant.logo" title="#variant.name" />
</div>
<div class="col-md-8">
<h4>#variant.name</h4>
</div>
</button>

Categories

Resources