我已经创建了一个自定义指令,用于将<rect>
和<circle>
等标记呈现为<svg>
元素。
我有一个形状模型,它只是一个具有各种属性的对象数组,例如width
,height
和stroke-width
。
这些形状由我的自定义指令
呈现为SVG<svg height="400" width="600">
<dr-shape ng-repeat="shape in shapes"></dr-shape>
</svg>
指令定义如下所示(评论很多):
app.directive('drShape', ['$compile', function($compile) {
// A helper function for adding attributes to an element.
var bindNgAttr = function(el, attribute, value) {
el.attr('ng-attr-' + attribute, '{{shape.' + attribute + '}}');
};
return {
restrict: 'E',
link: function(scope, element, attrs) {
// #makeNode simply creates a DOM node using `document.createElementNS`
// so that it can be appended to an SVG element. It also assigns
// any attributes on the directive.
var shape = makeNode(scope.shape.tagName, element, attrs);
var elementShape = angular.element(shape);
// This part iterates through a shape's attributes and attaches them
// to the created node. I'm doing this (rather than declaring them
// where the directive is used in the template because <circle> nodes
// take different attributes to <rect> nodes. Thus I can't hardcode them.
for (var attribute in scope.shape) {
// #isPublic simply ensures that we don't assign any '$' attributes.
if (isPublic(attribute, scope.shape[attribute])) {
// Here we use the helper defined above.
bindNgAttr(elementShape, attribute);
}
}
// Here I'm adding a click listener to the element. This works and
// when I click a <rect> I can see the console log. The fill color
// never seems to change in the browser however. I can only assume that
// the model data is being changed but the binding with the DOM has been
// broken.
elementShape.on('click', function() {
console.log('Clicked in directive');
scope.shape.fill = '#bada55';
});
element.replaceWith(shape);
// Not sure what this does. It comes from: http://goo.gl/ZoYpQv
attrs.$observe('value', function(value) {
scope['value'] = parseInt(value, 10);
$compile(shape)(scope);
});
}
};
}]);
当我使用一些形状数据运行时,我在浏览器中获得以下SVG:
<svg height="400" width="600">
<!-- ngRepeat: shape in shapes -->
<rect ngRepeat="shape in shapes" strokeWidth="3" ng-attr-stroke="{{shape.stroke}}" ng-attr-fill="{{shape.fill}}" ng-attr-x="{{shape.x}}" ng-attr-y="{{shape.y}}" ng-attr-width="{{shape.width}}" ng-attr-height="{{shape.height}}" ng-attr-tagname="{{shape.tagName}}" stroke="#aea086" fill="#fff" x="239" y="89" width="25" height="22" tagname="rect"></rect>
<!-- end ngRepeat: shape in shapes -->
<rect ngRepeat="shape in shapes" strokeWidth="3" ng-attr-stroke="{{shape.stroke}}" ng-attr-fill="{{shape.fill}}" ng-attr-x="{{shape.x}}" ng-attr-y="{{shape.y}}" ng-attr-width="{{shape.width}}" ng-attr-height="{{shape.height}}" ng-attr-tagname="{{shape.tagName}}" stroke="#a265e7" fill="#fff" x="233" y="6" width="12" height="43" tagname="rect"></rect>
<!-- end ngRepeat: shape in shapes -->
</svg>
Here's a JSFiddle with the above code
正如我在上面代码块的注释中解释的那样,操纵任何形状模型中的数据都不会更新相应的SVG DOM节点。
我尝试在点击处理程序中调用scope.$apply()
和scope.$digest()
,但它不会更改任何内容。 (编辑:这是不正确的 - 请参阅下面的答案。)
如何让我的数据更改在视图中生效?
答案 0 :(得分:0)
事实证明,调用scope.$apply()
实际上在点击处理程序中起作用。我不确定我在做什么让我觉得它没有。
elementShape.on('click', function() {
console.log('Clicked in directive');
scope.shape.fill = '#bada55';
scope.$apply();
});
我在JSFiddle中犯了一个错误,这个问题加剧了这个问题。 Here's a working fiddle
对不起,如果我浪费了任何人的时间!