I'm trying to do buttons like the upvote buttons here, a button tag, with svg and path inside.
The appearance is ok, no problems with that. The problem is that the path tag has an attribute that I want to get when I click the button, I'm not very good at this, so to get the attribute that I want I used:
e.target.children[0].children[0].attributes.
And it gets to an error that I know the reason: the element has no children nor attributes, the error depends on where I click, if I click the path, the error is that it's child doesn't have a child (cause path's child is undefined), and if I click the svg, the problem is that the svg's child's child doesn't have attributes (again because it's undefined). So to don't get those errors, I have to click in the button, where there isn't path nor svg.
What should I do to being able to click in any pixel of the button and getting the same answer? I don't even know why it detects that I'm clicking on the svg or path even when those elements haven't any event listener.
When I started doing those buttons, I didn't use the button tag, it was just svg, and the eventListener was in the path element, the problem is that with small paths, is hard to click, so I started trying to use the click listener in the svg and now I put all inside a button tag and tried using the listener in the button, and I got the errors that I mentioned.
My apologies for not posting the code, it's a little long and horrible.
Edit:
I tried to take the most important of the code:
<body>
<div id="buttonCont">
</div>
<script>
//Function that adds around 40 buttons.
function addButtons(){
buttonCont = document.getElementById("buttonCont");
i = 0;
while (paths(i) != ``) {
buttonCont.innerHTML = `
<button >
<svg >
<path pathNumber="${i}" d=""/>
</svg>
</button>`;
i ;
}
}
function on_load(){
addButtons();
exButtons = document.getElementsByClassName("exButton");
for(let i = 0; i < exButtons.length; i ){
exButtons[i].addEventListener("click", getNumber, false);
}
}
//This is the function with the problem.
function getNumber(e){
pNumber = e.target.children[0].children[0].attributes.pathNumber.nodeValue;
console.log(pNumber);
}
window.addEventListener("load", on_load, false);
</script>
After some hours I noticed that e.target returns the element that I clicked, not the element that has the listener, so anything inside the button is a different target. I'm looking a solution in javascript that allows me to get the button element with the click eventListener.
CodePudding user response:
Passing in this
with your listener will always ensure your starting point is the same. For example:
<div onClick="getKey(this)">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path
data-key="12345"
d="M 10,30
A 0,10 0,0,1 30,40
A 0,10 0,0,1 90,40"/>
</svg>
</div>
<script>
function getKey(button) {
let key = button.querySelectorAll('path')[0].dataset.key;
alert('key is ' key)
}
</script>
In the above code, getKey()
will always receive the div
element so that you can reliably know how many children deep you need to dig.
Additionally, you can use button.querySelectorAll('path')[0]
to isolate the path
tag within the button so you don't have to cascade down the children
properties.
Here's a working JSFiddle: https://jsfiddle.net/sLp2qtde/1/
CodePudding user response:
Well, I found a solution, using querySelectorAll as verl suggested, I changed the function getNumber, original:
function getNumber(e){
pNumber = e.target.children[0].children[0].attributes.pathNumber.nodeValue;
console.log(pNumber);
}
New one:
function getNumber(e){
var object;
if(e.target.querySelectorAll('path')[0] == undefined){
object = e.target;
} else {
object = e.target.querySelectorAll('path')[0];
}
pNumber = object.attributes.pathNumber.nodeValue;
console.log(pNumber);
}
So now I don't modify the HTML, just the function that was giving problems to me.