0

Many old libraries rely on className to identify their context.

So a click handler can look like this:

function click(event)
{
   if (event.target.className.indexOf('something')!= -1){
       // Do something
   }
}

But this will fail if the target element is an svg element. The reason is that svg className is an object of type SVGAnimatedString

Is there any temporary workaround to avoid issues with old code? Change the handler is not an option as it is unclear how many libraries have this code and changing library code could be impossible.

Changing the SVG to some other element is not an option as the SVG is a part of a 3rd party control.

Update:

"Is there any temporary workaround to avoid issues with old code?" Seems unclear based on the comments. My goal is to see if there is any polyfill or any other technique that I can use to temporarily make SVG elements have their className as string until 3rd party libraries catch up. Then I will update the 3rd party libraries and revert this code.

As of now - simply overwriting the className doesn't seem to be possible as it only seems to have getter and no setter for SVG elements.

function oldModuleHandler(e) {
  if (e.className.indexOf("initial") > -1 || e.className.indexOf("fixed") > -1) {
    alert('Behaves as expected.');
  }
}

function theFix(e) {
  e.className = "fixed";
}
<html>

<head>

</head>

<body>

  <div style="border:2px solid silver;">
    <h2>Demo:</h2>
    Click on the left square, it is a div and it will have it's color changed to green because .className.indexOf will go through just fine. Same does not apply for SVG.<br/> <br/><br/>
    <div onclick="theFix(this); oldModuleHandler(this)" class="initial">
    </div>

    <svg class="initial" onclick="theFix(this); oldModuleHandler(this)"></svg>
    <div style="clear:both;"></div>
  </div>
  <style>
    .fixed {
      background: green !important;
      width: 80px;
      height: 80px;
      float: left;
    }
    
    .initial {
      background: transparent;
      border: 1px solid black;
      width: 80px;
      height: 80px;
      float: left;
    }
  </style>
</body>

</html>

Update 2 I added a small code to demonstrate the issue. If you click on the left square (it is a div) - it will work just fine. If you click on the right square - the SVG - it will not work because .className.indexOf() will throw an error.

Pavel Donchev
  • 1,809
  • 1
  • 17
  • 29
  • 1
    You seem to have set the requirements sufficiently strictly to ensure that no solution is possible. – Robert Longson Nov 21 '20 at 06:34
  • Thanks, @RobertLongson, actually - I was looking for some clever hack or workaround that I can use in order to allow time for 3rd party libraries to catch up. I assume relying on event.target.className being a string is a bug now, after we have a valid (according to the specifications) case where this is not true. So my goal is to workaround it on my side until the 3rd party vendors fix their code, update libraries, revert the "workaround". – Pavel Donchev Nov 22 '20 at 00:43
  • 1
    SVG has been around for 20 years now. If the libraries had any intention of supporting it they would have by now. If you're using SVG, move to better libraries. – Robert Longson Nov 22 '20 at 06:48
  • 1
    And as to your final observation, it's wrong. There is a setter for className in SVG. – Robert Longson Nov 22 '20 at 07:22
  • I think you are right for the setter. I added a small example. Then - also I found that the W3C spec here: https://www.w3.org/TR/2015/WD-SVG2-20150709/types.html#InterfaceSVGElement says className may be deprecated at some point. Not sure what to think or how to act. I will have to research if switching away from SVG could be a solution. – Pavel Donchev Nov 23 '20 at 04:16

1 Answers1

0

You might use getAttribute and setAttribute OR 'classList methods :

function oldModuleHandler(e) {
  var c = e.getAttribute('class');
  if (~c.indexOf("initial") || ~c.indexOf("fixed")) {
    alert('Behaves as expected.');
  }
}

function theFix(e) {
  e.className = "fixed";
  e.setAttribute('class', 'fixed')
  // OR 
  e.classList.add('fixed')
}
.fixed {
      background: green !important;
      width: 80px;
      height: 80px;
      float: left;
    }
    
    .initial {
      background: transparent;
      border: 1px solid black;
      width: 80px;
      height: 80px;
      float: left;
    }
<div style="border:2px solid silver;">
    <h2>Demo:</h2>
    Click on the left square, it is a div and it will have it's color changed to green because .className.indexOf will go through just fine. Same does not apply for SVG.<br/> <br/><br/>
    <div onclick="theFix(this); oldModuleHandler(this)" class="initial">
    </div>

    <svg class="initial" onclick="theFix(this); oldModuleHandler(this)"></svg>
    <div style="clear:both;"></div>
  </div>

And/Or look at Proxy API.

Kosh
  • 16,966
  • 2
  • 19
  • 34