NicholasFolk NicholasFolk - 2 months ago 9
jQuery Question

Getting siblings of g element in SVG is returning all similar level elements from other SVGs on the page using jquery. Why?

I'm currently creating multiple svgs on a single page, where each svg usually has three buttons to click. Each button is a rect and text element grouped by a g element. I want a user to click a button, and set a border on that button to show the selection. This is currently being done by adding a .selected class to the chosen button and removing .selected from any sibling. When I try to query the siblings and remove the .selected class, I am somehow removing the class from other svgs on the page. I'm guessing it's because jquery and svg don't play nice, so I'm thinking of switching to an svg library instead, but until now I've been able to work around most issues cleanly. Code below:

<!-- Index.html -->
...
<svg ...//attributes//...>
<g class="button1">
<rect class="" ...//attributes//...></rect> // Clicking this one...
<text ...//attributes//...> button 1 </text>
</g>
<g class="button2">
<rect class="" ...//attributes//...></rect>
<text ...//attributes//...> button 2 </text>
</g>
</svg>
...
<svg ...//attributes//...>
<g class="button1">
<rect class="" ...//attributes//...></rect> // ...affects these elements
<text ...//attributes//...> button 1 </text>
</g>
<g class="button2">
<rect class="" ...//attributes//...></rect>
<text ...//attributes//...> button 2 </text>
</g>
</svg>


Jquery:

$("g").click(function () {
var selection = $(this);
var siblings = selection.siblings();
for (var sibling in siblings) {
$(sibling).find("rect").attr("class", "");
}
selection.find("rect").attr("class","selected");
});


I've also tried using closest("svg").children("rect"), closest("g").children("rect") after encompassing the all buttons in another g element, parent("g").children("rect"). All do the same thing.

EDIT: MCVE (I hope): https://jsfiddle.net/c1cceya9/

Answer

Your problem is this code:

   for (var sibling in siblings) {
       $(sibling).find("rect").attr("class", "");
   }

You don't need to loop through the siblings yourself, jQuery will do that for you. All you need is:

$("g").click(function () {
   var selection = $(this);
   selection.siblings().find("rect").attr("class", "");
   selection.find("rect").attr("class","selected");   
});

Your code was not doing what you think it was. It was looping through the jQuery object, not an array of siblings. The jQuery object contains all sorts of fields including pointers to the document. That's why it was clearing all selections.

Working demo

$("g").click(function () {
   var selection = $(this);
   selection.siblings().find("rect").attr("class", "");
   selection.find("rect").attr("class","selected");   
});
.selected {
  stroke: white;
  stroke-width: 2px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg height="100" width="200">
    <rect height="100" width="200" fill="black"></rect>
     <g class="button1">
         <rect class="" x="10"  y="10" height="80" width="80" fill="red"></rect>   // Clicking this one...
         <text x="25"  y="50" fill="white"> button 1 </text>
     </g>
     <g class="button2">
         <rect class="" x="110"  y="10" height="80" width="80" fill="blue"></rect>
         <text  x="125"  y="50" fill="white"> button 2 </text>
     </g>
 </svg>
 <svg height="100" width="200">
    <rect height="100" width="200" fill="black"></rect>
     <g class="button1">
         <rect class="" x="10"  y="10" height="80" width="80" fill="red"></rect>   // Clicking this one...
         <text x="25"  y="50" fill="white"> button 1 </text>
     </g>
     <g class="button2">
         <rect class="" x="110"  y="10" height="80" width="80" fill="blue"></rect>
         <text  x="125"  y="50" fill="white"> button 2 </text>
     </g>
 </svg>