问题
I am learning angularjs and I am trying use ng-repeat to create an svg graph.
I have this html:
<svg>
<g id="g_{{$index}}" ng-repeat="i in range" ng-cloak>
<rect x="{{i / 5}}" y="{{i / 5}}" width="{{i / 5}}" height="{{i / 5}}"></rect>
</g>
</svg>
the 'range' is just a simple array which is defined in controller like this:
$scope.range = [100, 200, 300];
the html is working; the rects are rendered on my page.
However, Chrome keeps throwing the following error:
Error: Invalid value for <rect> attribute height="{{i / 5}}" js/angular.js:1584
JQLiteClone js/angular.js:1584
JQLite.(anonymous function) js/angular.js:2163
publicLinkFn js/angular.js:3862
ngRepeatWatch js/angular.js:13641
Scope.$digest js/angular.js:7889
Scope.$apply js/angular.js:8097
js/angular.js:961
invoke js/angular.js:2857
resumeBootstrapInternal js/angular.js:959
bootstrap js/angular.js:973
angularInit js/angular.js:934
js/angular.js:14756
fire js/jquery-2.0.0.js:2863
self.fireWith js/jquery-2.0.0.js:2975
jQuery.extend.ready js/jquery-2.0.0.js:398
completed js/jquery-2.0.0.js:93
It seems that it does not quite like what I am doing...
Does anyone have an idea why I'm receiving this error?
回答1:
The problem is Chrome sees the Angular interpolation str as an invalid value for those attributes (since at least at one time the element actually exists in the DOM -- though invisibly -- with "invalid" values). I have written a solution that is in line with other Angular solutions as to browser handling of special attributes where instead of using x, y, width, and height, you specify ng-x, ng-y, ng-width, and ng-height and the real attributes are set after the values are interpolated.
Here is the solution on JSFiddle. I'm going to submit a patch to Angular to see if we can get this in the core.
HTML
<div ng-app="SampleApp" ng-controller="MainCtrl">
<svg>
<g id="g_{{$index}}" ng-repeat="i in range" ng-cloak>
<rect ng-x="{{i / 5}}" ng-y="{{i / 5}}" ng-width="{{i / 5}}" ng-height="{{i / 5}}"></rect>
</g>
</svg>
</div>
JS
angular.module('SampleApp', [], function() {})
.directive('ngX', function() {
return function(scope, elem, attrs) {
attrs.$observe('ngX', function(x) {
elem.attr('x', x);
});
};
})
.directive('ngY', function() {
return function(scope, elem, attrs) {
attrs.$observe('ngY', function(y) {
elem.attr('y', y);
});
};
})
.directive('ngWidth', function() {
return function(scope, elem, attrs) {
attrs.$observe('ngWidth', function(width) {
elem.attr('width', width);
});
};
})
.directive('ngHeight', function() {
return function(scope, elem, attrs) {
attrs.$observe('ngHeight', function(height) {
elem.attr('height', height);
});
};
});
function MainCtrl($scope) {
$scope.range = [100, 200, 300];
}
回答2:
Markus' comment to use late binding is best.
Ie. prefix your attribute with either 'ng-attr-', 'ng:attr:' or 'ng_attr_', like this:
<rect ng:attr:x="{{i / 5}}" ng:attr:y="{{i / 5}}" ng:attr:width="{{i / 5}}" nng:attr:height="{{i / 5}}"></rect>
来源:https://stackoverflow.com/questions/16318768/use-svg-with-angularjs-ng-repeat