0

I have a svg map and I am putting that into object and I am trying to create all path with id clickable.

For that I am doing this to get svg object :

 let a = document.getElementById("biharsvg")

And I am putting that into svg doc like this:

   var svgDoc = a.contentDocument;

And now I am getting all the values of certain class using this:

  let de = svgDoc.getElementsByClassName("fil0");

I can also get the attribute id value using this:

var i;
for (i = 0; i < de.length; i++) {
  var j = de[i].getAttribute("id");
   console.log(j);

}

I want to add a click event on each attribute id and get the value when I am doing this:

var i;
for (i = 0; i < de.length; i++) {
  var j = de[i].getAttribute("id");
   console.log(j);
  svgDoc.getElementById(j).onclick = function() {
      modal.style.display = "block";  
        console.log(this.getAttribute("id"));
    }
}

This is working fine and I am getting all the values but in jquery I can use this:

 $(de).click(function(){
   alert(this.getAttribute("id"));
});

Is there any way I can use something like this in javascript without loop. My question is what is the best possible way to make this work in javascript.

7
  • No there isn't. Why not use jQuery? Commented Jun 27, 2018 at 9:45
  • I am trying to understand can I do this in plain javascript without loop Commented Jun 27, 2018 at 9:46
  • No you can't. Why not use jQuery? Commented Jun 27, 2018 at 9:46
  • 1
    Well the basic principle of event delegation “works” in vanilla JS as well, if you want to avoid having to add an individual handler to each single element. Commented Jun 27, 2018 at 9:48
  • jQuery also uses a loop, if you write $(de).click( then jQuery internally loops over all element in the result set create by $(de) and attaches the given event handler to each of these elements, they just "hide" it in their code. Commented Jun 27, 2018 at 9:48

3 Answers 3

1

The javascript version for jQuery's

$(de).click(function(){
   alert(this.getAttribute("id"));
});

would be something like

Array.from(de).forEach( function(el){
    el.addEventListener('click', function() {
        alert(this.getAttribute("id"));
        // or "this.id" should work too
    });
});

To be noted, when doing $(de).click(function(){...} with jQuery, it also loops, internally.


And as commented, with arrow functions you could shorten the code even more

Array.from(de).forEach(el => el.addEventListener('click', function () {...}))

var de = document.querySelectorAll('span');

Array.from(de).forEach(el => el.addEventListener('click', function () {
  alert(this.id);
}))
span {
  display: inline-block;
  padding: 20px;
  margin: 0 5px;
  border: 1px dotted black;
}
span::after {
  content: attr(id)
}
<span id="nr1">click </span>
<span id="nr2">click </span>
<span id="nr3">click </span>


Updated based on a comment.

The main difference between your existing loop and the above is, the above is more efficient, with a cleaner/shorter code.

In your original loop

var i;
for (i = 0; i < de.length; i++) {
  var j = de[i].getAttribute("id");
   svgDoc.getElementById(j).onclick = function() {
      modal.style.display = "block";  
        console.log(this.getAttribute("id"));
    }
}

you iterate through the element array de, get its id and then make a new call using getElementById to get the element you already have.

With the kept syntax/logic, your existing code could been simplified to something like this

for (var i = 0; i < de.length; i++) {
    de.onclick = function() {
        modal.style.display = "block";  
        console.log(this.getAttribute("id"));
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Is it the same thing which I am doing inside my loop or it is different or better version. Need explanation
So with an extra line of javascript, and you can drop a 240kb library ... seems like a good trade to me :)
@user2480754 It is a more efficient and cleaner/shorter way to loop an array of e.g. elements, your existing for..loop does the same job though
@Pete Of course (updated with a note)...were focusing on the forEach vs jQuery internal loop
@user2480754 I updated my answer with an explanation. Let me know if it made sense.
|
0

I just want to show an alternative way, pointed out by CBroe, where a click on the document is checked for its event target:

let de = Array.from(mylist.getElementsByClassName("fil0"));
document.addEventListener('click', function(e) {
  const el = e.target;
  if (de.indexOf(el) < 0) return false;
  alert(el.innerHTML);
});
<ul id="mylist">
  <li>one</li>
  <li class="fil0">two*</li>
  <li class="fil0">three*</li>
</ul>

<p>* has click event assigned indirectly</p>

This has the additional benefit that it only uses a single handler function, and if the indexOf() condition is changed to something like classList.contains(), it will even work for elements that don't exist yet.

Comments

0

I find for..of to be the most convenient and readable syntax:

for (const element of svgDoc.getElementsByClassName("fil0")) {
  console.log(element.id);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.