Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix(jqLite): use get/setAttribute so that jqLite works on SVG #4129

Closed
wants to merge 1 commit into from

Conversation

btford
Copy link
Contributor

@btford btford commented Sep 24, 2013

jqLite previously used elt.className to add and remove classes from a DOM Node, but because the className property is not writable on SVG elements, it doesn't work with them. This patch replaces accesses to className with get/setAttribute.

Note that jQuery still uses className, so developers who include jQuery will have this functionality broken. The solution for them is to have jQuery fix it. :)

classList was also considered as a solution, but because only IE10+ supports it, we have to wait.

Closes #3858

@mary-poppins
Copy link

@btford you are both fragrant and a talented developer.

@@ -279,17 +279,17 @@ function JQLiteData(element, key, value) {
}

function JQLiteHasClass(element, selector) {
return ((" " + element.className + " ").replace(/[\n\t]/g, " ").
return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not necessary, reading className property is not an issue for us and the property is updated with every setAttribute call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is; SVG Nodes are special. className is an object for them :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@btford is right here. In this case, the className is of type SVGAnimatedString. This has a property baseVal that you can read if you like but writing to it has no affect on the actual CSS class attribute of the element. getAttribute and setAttribute seem like the only reasonable solution.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup

@petebacondarwin
Copy link
Contributor

Shouldn't the spec/test be in jqLiteSpec.js rather than animateSpec.js?

jqLite previously used `elt.className` to add and remove classes from a DOM Node, but
because the className property is not writable on SVG elements, it doesn't work with
them. This patch replaces accesses to `className` with `get/setAttribute`.

`classList` was also considered as a solution, but because only IE10+ supports it, we
have to wait. :'(

Closes angular#3858
@btford
Copy link
Contributor Author

btford commented Sep 24, 2013

@petebacondarwin I don't even know anymore. We need to test that $animate delegates to jqLite regardless of whether jQuery is included, but also that jqLite works with SVG Elements. @IgorMinar what do you think?

@petebacondarwin
Copy link
Contributor

The work around for JQuery is to use the 3rd party plugin I linked to in the original issue.

@@ -156,7 +156,9 @@ var $AnimateProvider = ['$provide', function($provide) {
className = isString(className) ?
className :
isArray(className) ? className.join(' ') : '';
element.addClass(className);
forEach(element, function (element) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't forEach try to iterate over element properties if element is not an array? I suspect that we need an isArray check here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The element passed to addClass should be a jQuery/jqLite element, so it's always an ArrayLike object, making forEach treat is as an array instead of an object

So forEach'ing it allows you to iterate over each DOM node inside the collection.

Maybe a change in the naming of the variable would make this more clear?
That's related to style more than anything else

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what @rodyhaddad said.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh. ok. that makes sense.

@IgorMinar
Copy link
Contributor

ok, this looks good to me.

just check the forEach and make sure it handles single elements correctly. then merge.

@btford
Copy link
Contributor Author

btford commented Sep 28, 2013

Landed as c785267.

@btford btford closed this Sep 28, 2013
@edokeh
Copy link

edokeh commented Nov 4, 2013

But this doesn't work in IE7.
ng-show directive is broken in IE7 cause add "ng-hide" class to element doesn't work.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ng-show stopped working for SVG elements in 1.2.0rc1
6 participants