Reputation: 9480
I blame my own stupidity, but I can't for the life of me understand why jQuery (2.1.4) can't directly change the class of an SVG element (or child elements) using it's class functions? I was messing around with trying to make an SVG manipulation plugin for jQuery, and I was testing all kinds of things to make the class changeable (yes, I've tried the common SVG libraries; no, I don't care for them). I ended up settling on my current version which intelligently overrides the original jQuery.addClass()
function. I check if the jQuery element's array contains an SVG type node and if it does I use my custom function, otherwise, I pass it back to the original jQuery function. This seems to work so far. That being said, my "custom" function is the exact same code as the jQuery function because I copied it from the source on GitHub. So if it works with my "custom" function, why doesn't it simply work with the default jQuery function?
Here's the code I have so far. Syntax wise my code is different to match my style, but it effectively does the exact same thing as the original jQuery code.
(function ($) {
var element,
jQueryFunctions = {
addClass: $.fn.addClass
};
var addClass = function (
elements,
value) {
var proceed = typeof (value) === "string" && value;
if (!proceed) {
return this;
}
for (var i = 0, j, l = elements.length, element, klasses = (value || "").match(/\S+/g) || [], klass, currentValue, current, finalValue; element = elements[i], i < l; i++) {
currentValue = element.getAttribute && element.getAttribute("class") || "",
current = element.nodeType === 1 && (" " + currentValue + " ").replace(/[\t\r\n\f]/g, " ");
if (!current) {
return;
}
j = 0;
while (klass = klasses[j++]) {
if (current.indexOf(" " + klass + " ") < 0) {
current += klass + " ";
}
finalValue = jQuery.trim(current);
if (currentValue !== finalValue) {
element.setAttribute("class", finalValue);
}
}
}
};
var hasSvgNodes = function (
elements) {
var returnValue = true;
for (var i = 0, l = elements.length, element; element = elements[i], i < l; i++) {
returnValue = returnValue && (element.nodeName === "svg");
}
return returnValue;
};
$.fn.svg = function () {
return element = this;
};
$.fn.addClass = function (
value) {
if (!hasSvgNodes(this)) {
jQueryFunctions.addClass.apply(this, arguments);
} else {
addClass(this, value);
}
return this;
};
$.fn.svg.test = function () {
element.addClass("Red");
};
}(jQuery));
Upvotes: 0
Views: 89
Reputation: 9480
@Paul's answer made me wonder a bit because the code I took was from the current source on GitHub. I double checked just in case I did pull from an older version, and sure enough it was the latest. So, I decided to double check the release notes for 3.0.0 a1, and I found my answer. Apparently the jQuery team decided to ever so slightly change their stance on the Won't Fix policy and allow direct manipulation of SVG elements' class attributes. That is the code that's currently up there now and what I was copying.
Here's the discussion thread and commit for reference. So, jQuery does do class manipulation by default, it's just in the next version. For what I'm working on, I don't mind going to the alpha so it works out for me.
I'll still be making my own plug in for SVG specific tasks which are specific to my needs, but with the class issue resolved, it should be much easier now.
Upvotes: 0
Reputation: 1
Note, workaround ; svg
, jsfiddle forked from @PaulLeBeau 's Answer
Try utilizing HTMLElement.dataset
to apply css
$().ready(function() {
$("#test")[0].dataset.class = "red";
});
[data-class="red"] {
fill: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js">
</script>
<svg>
<rect id="test" width="300" height="150" />
</svg>
Upvotes: 0
Reputation: 101800
@Alex is correct. It doesn't work (demo). It used to once upon a time (eg. in the 1.1 branches) but it no longer does.
The reason is basically because the type of the className
property is different for SVG elements and HTML elements. In HTML elements, it's a string. In SVG elements it's an SVGAnimatedString
.
The addClass()
code expects it to be a string.
var htmlelem = document.getElementById("htmlelem"),
svgelem = document.getElementById("svgelem");
alert("HTML = "+(typeof htmlelem.className) + ". SVG = "+(typeof svgelem.className));
<svg>
<rect id="svgelem" width="300" height="150"/>
</svg>
<div id="htmlelem"></div>
The reason your own version is working is because it looks like you have taken code from an older branch of jQuery. It is definitely not the 2.1.4 version of addClass
.
Upvotes: 2