-
Notifications
You must be signed in to change notification settings - Fork 27.5k
what happened to ng-bind-attr? #1925
Comments
we took it out because it didn't seem necessary. previously the template compiler depended on ng-bind-attr directive, but after a refactoring it was not needed any more. this is where the attr interpolation is detected currently: Line 477 in 649b892
if we were to reintroduce the support for ngBindAttr it should work consistently with the regular interpolation. I wonder if that means that we'd need to special case it in the compiler rather than implementing it as a regular directive. |
Question: Can ng-bind-attr handle case-sensitive attributes? For example the viewBox attribute on is case sensitive. I was trying out the workaround shown for the svg warnings in #1050 but since ng treats attributes as case-insensitive I couldn't make it work for viewBox. A shame, really, because with ng:attr-viewBox or perhaps late:viewBox you could have a generic prefix to do late attribute additions in the same syntax as normal ones. Perhaps a "late:" prefix could be used specifically to do late binding on attributes, leaving the attribute case exactly like it is? Then ng:src could also be written as late:src for example. |
I'd welcome a resolution of this issue as angular bindings to SVG attributes currently fail in Chrome. If the values are interpolated then the fixes suggested in issue #1050 also fail. The following nasty hack does solve the problem by aliasing 'svgXXX' attributes to 'XXX' similar to ngSrc etc. It assumes templates for SVG include things like
The hack inserts // hack to avoid svg attribute errors - uses svgXXX alias for XXX
if(name.slice(0,3)==='svg') {
attr.$set(name.slice(3).toLowerCase(), value);
} in function addAttrInterpolateDirective after attr.$set(name, value); at: Line 1040 in 649b892
|
@gmp26 you shouldn't do the .toLowerCase(), otherwise you can't set the viewBox attribute which is case sensitive. I do like the generic prefix but would prefer something like "late:". |
Agreed - there may be other cases apart from SVG and 'late' would then make more sense. if(name.slice(0,4)==='late') {
attr.$set(name.slice(4), value);
} |
Hmm, isn't the colon a valid syntax in all browsers? Then "late:" would be a very specific prefix that is very unlikely to be part of real attributes. BTW, you probably meant Wout. On Feb 11, 2013, at 11:59 , Mike Pearson [email protected] wrote:
|
I've just sent a PR that implements this feature. I hope it gets reviewed soon. |
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 attributes like ng-href or ng-src. This commit is a more general solution that allows prefixing any attribute with "ngAttr", "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 ngAttrCx="{{cx}}" ng-attr-cy="{{cy}}" ng:Attr:r="{{r}}"></circle> </svg> Closes angular#1925
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 angular#1050 Closes angular#1925
👍 |
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 angular#1050 Closes angular#1925
Hello, I'm also looking to use ng-bind-attr, what should I use instead? |
@wcandillon See description in cf17c6a |
@pkozlowski-opensource thank you so much! that solves it. Is there any reason why this directive is using string interpolation syntax? It feel inconsistent with ng-bind. |
this appears to be missing from the docs? |
There still seems to be an issue with case sensitive attributes, which is problematic for SVG. For example |
Hmmm... It may not be so easy to fix. The attribute is normalized in the Angular-way so we can trigger functionality disregarding which notation is used in its naming. In this line we convert the attribute to lowercase. I recall the purpose of that is avoiding that As I said before, I can't think of an easy fix:
I personally find the later more powerful and it may be a nice addition to Angular. I could prepare a PR this weekend if there's someone interested in this feature. Sadly, the core team is overwhelmed with myriads of PR so I wouldn't be too optimistic about it being considered... |
👍 for the ng-attrs object idea! On Tue, Jan 21, 2014 at 9:16 PM, Luis Ramón López
|
I haven't tested yet if PR #4269 works for this, but I came up with a hack/workaround that I used for this a while back. Posted here in case it is helpful to anyone. .directive('caseSensitive', function() {
return {
link: function(scope, element, attr) {
scope.attr = attr;
var caseSensitive = attr.caseSensitive.split(',');
angular.forEach(caseSensitive, function(a) {
var lowercase = a.toLowerCase();
scope.$watch('attr[lowercase]', function() {
element[0].setAttribute(a, element[0].getAttribute(lowercase));
});
});
}
};
}) Example Usage: <marker case-sensitive="refX,refY" viewBox="0 0 10 10" markerWidth="30"
markerHeight="30" ng-attr-refX="{{ref.x}}" ng-attr-refY="{{ref.y}}" orient="auto">
</marker> |
Nice solution @stanleygu ! Makes me wonder if it's not easier to have angular do the same by default for a hard-coded list of known-problematic attributes... Then it would all Just Work... |
Did something break recently regarding ng-attr-*? I can't seem to get it to work... http://plnkr.co/edit/J0scPYKFb2udjRPYiJYG?p=preview Just need a sanity check. |
Until someone looks into it, you could just use
|
@lrlopez Yup, for sure. It's just throwing warnings in the console that I'm doing a little fallback dance to avoid for the moment. |
For what it's worth, I needed a way to set attributes without using interpolation, and came up with this very simple directive the gets the job done: Code: https://gist.github.com/mbenford/dd7556f01963f49e5c7d |
Based off of angular/angular.js#1925
I need to write something like
because if I instead write
the browser throws errors like
because Angular has not yet replaced the values of these attributes by the time the element is parsed.
It looks like Angular used to have ng-bind-attr which would solve exactly this problem, but it was taken out in 5502 / https://github.com/angular/angular.js/blob/master/CHANGELOG.md#100rc3-barefoot-telepathy-2012-03-29 and I have been unable to find any documentation of why it was taken out and what you're supposed to use instead. Can anyone shed some light on this?
The text was updated successfully, but these errors were encountered: