Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

"invalid value for attribute" errors at startup for svg elements #1050

Closed
dwhipp opened this Issue · 9 comments

8 participants

@dwhipp

Using chrome Version "20.0.1132.27 beta" (but also seen on other versions)

For this html (obviously it's simplified from the original):

<html ng-app>
  <head>
    <script src="http://code.angularjs.org/angular-1.0.0rc12.min.js"></script>
  </head>
  <body>
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
      <rect x="{{0}}" y="{{0}}" width="{{100}}" height="{{100}}" fill="red"/>
    </svg>
  </body>
</html>

it draws the expected rectangle, but when I look in the javascript console I see:

Error: Invalid value for attribute x="{{0}}" bug.html:7
Error: Invalid value for attribute y="{{0}}" bug.html:7
Error: Invalid value for attribute width="{{100}}" bug.html:7
Error: Invalid value for attribute height="{{100}}" bug.html:7

that apparently come from before the values are evaluated. They seem harmless, but are distracting (the real code generates a couple of thousand such errors, due to ng-repeat -- see http://dave.whipp.name/tutorial/anti-alias.html).

@geelen

Is there a directive or another Angular technique to get around this error? Ng-cloak isn't sufficient.

@mtiller

Sadly, I've run into this exactly same issue. Presumably Chrome is "evaluating" the SVG before AngularJS has a chance to go in and mess with the DOM? (and rightfully cannot evaluate the string "<[ 100+v.row*100 ]>" down to a number with Angular's help).

@vsirisanthana

I have had the same problem. Finally, I decided to write my own directives:

angular.module('yourmodule.directives', [])
    .directive('ngX', function() {
        return function(scope, element, attrs) {
            scope.$watch(attrs.ngX, function(value) {
                element.attr('x', value);
            });
        };
    })

Then, use ng-x attribute instead of x:

<circle ng-x="{{ x }}" y="0" r="5"></circle>

Finally got rid of annoying error messages.

@mtiller

That is an excellent solution. I will try it out. However, I wonder if I will have to create a whole bunch of directives for all the attributes that are affected.

Thanks.

@rkirov
Collaborator

Similarly to ngHref and ngSrc you can do

angular.forEach(['x', 'y', 'width', 'height'], function(name) {
  var ngName = 'ng' + name[0].toUpperCase() + name.slice(1);
  myModule.directive(ngName, function() {
    return function(scope, element, attrs) {
      attrs.$observe(ngName, function(value) {
        attrs.$set(name, value); 
      })
    };
  });
});
@vsirisanthana

@mtiller I think so. I had to create a whole bunch of directives for all the attributes as well. But, as @rkirov suggested, you can use a loop to do that.

@rkirov I've never used attrs.$observe and attrs.$set. Are those better than using scope.$watch and element.attr? What are the differences?

@skivvies skivvies referenced this issue from a commit in getlantern/lantern-ui
_pants workaround for angular/angular.js#1050 d10146f
@skivvies

Thanks for sharing that snippet, @rkirov, super helpful! Strange problem though: If you use that for "d" attributes as well, and try to set the value to empty string, resulting in elem.setAttribute("d", "") where elem is a path element, Chrome will give Error: Problem parsing d="" in the error console. But according to http://www.w3.org/TR/SVGTiny12/paths.html#DAttribute d="" is perfectly valid, and this is the way to disable rendering of the path, which sometimes you need. Anyone have any idea what's going on here? Is this a WebKit bug?

@skivvies

Is this a WebKit bug?

Yes.

@lrlopez

It seems #1925 is a duplicate of this issue. I didn't notice this one, sorry.

There is a pending PR (#2061) that solves it using prefixes on the attributes that need late binding.

Unfortunately, as @skivvies pointed out, the problem about d="" is a WebKit bug...

@lrlopez lrlopez referenced this issue from a commit
Commit has since been removed from the repository and is no longer available.
@lrlopez lrlopez referenced this issue from a commit
Commit has since been removed from the repository and is no longer available.
@lrlopez lrlopez referenced this issue from a commit
Commit has since been removed from the repository and is no longer available.
@lrlopez lrlopez referenced this issue from a commit in lrlopez/angular.js
@lrlopez lrlopez feat($compile): Allow late binding attributes
Sometimes is not desirable to use interpolation on attributes because
the user agent parses them before the interpolation takes place. I.e:

<svg>
  <circle cx="{{cx}}" cy="{{cy}}" r="{{r}}"></circle>
</svg>

The snippet throws three browser errors, one for each attribute.

For some attributes, AngularJS fixes that behaviour introducing special
directives like ng-href or ng-src.

This commit is a more general solution that allows prefixing any
attribute with "ng-attr-", "ng:attr:" or "ng_attr_"  so it will
be set only when the binding is done. The prefix is then removed.

I.e:
<svg>
  <circle ng_attr_cx="{{cx}}" ng-attr-cy="{{cy}}" ng:Attr:r="{{r}}"></circle>
</svg>

Closes #1050
Closes #1925
638e6fd
@IgorMinar IgorMinar referenced this issue from a commit in IgorMinar/angular.js
@lrlopez lrlopez feat($compile): Allow late binding attributes
Sometimes is not desirable to use interpolation on attributes because
the user agent parses them before the interpolation takes place. I.e:

<svg>
  <circle cx="{{cx}}" cy="{{cy}}" r="{{r}}"></circle>
</svg>

The snippet throws three browser errors, one for each attribute.

For some attributes, AngularJS fixes that behaviour introducing special
directives like ng-href or ng-src.

This commit is a more general solution that allows prefixing any
attribute with "ng-attr-", "ng:attr:" or "ng_attr_"  so it will
be set only when the binding is done. The prefix is then removed.

I.e:
<svg>
  <circle ng_attr_cx="{{cx}}" ng-attr-cy="{{cy}}" ng:Attr:r="{{r}}"></circle>
</svg>

Closes #1050
Closes #1925
4e27938
@IgorMinar IgorMinar closed this issue from a commit
@lrlopez lrlopez feat($compile): add attribute binding support via ngAttr*
Sometimes is not desirable to use interpolation on attributes because
the user agent parses them before the interpolation takes place. I.e:

<svg>
  <circle cx="{{cx}}" cy="{{cy}}" r="{{r}}"></circle>
</svg>

The snippet throws three browser errors, one for each attribute.

For some attributes, AngularJS fixes that behaviour introducing special
directives like ng-href or ng-src.

This commit is a more general solution that allows prefixing any
attribute with "ng-attr-", "ng:attr:" or "ng_attr_"  so it will
be set only when the binding is done. The prefix is then removed.

Example usage:

<svg>
  <circle ng-attr-cx="{{cx}}" ng-attr-cy="{{cy}}" ng:attr-r="{{r}}"></circle>
</svg>

Closes #1050
Closes #1925
cf17c6a
@IgorMinar IgorMinar closed this in cf17c6a
@jesselpalmer jesselpalmer referenced this issue from a commit
@lrlopez lrlopez feat($compile): add attribute binding support via ngAttr*
Sometimes is not desirable to use interpolation on attributes because
the user agent parses them before the interpolation takes place. I.e:

<svg>
  <circle cx="{{cx}}" cy="{{cy}}" r="{{r}}"></circle>
</svg>

The snippet throws three browser errors, one for each attribute.

For some attributes, AngularJS fixes that behaviour introducing special
directives like ng-href or ng-src.

This commit is a more general solution that allows prefixing any
attribute with "ng-attr-", "ng:attr:" or "ng_attr_"  so it will
be set only when the binding is done. The prefix is then removed.

Example usage:

<svg>
  <circle ng-attr-cx="{{cx}}" ng-attr-cy="{{cy}}" ng:attr-r="{{r}}"></circle>
</svg>

Closes #1050
Closes #1925
df3eb30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.