在指令Angular.js更新SVG模板 [英] Angular.js updating SVG templates in directives
问题描述
前段时间我问了一下<一个href=\"http://stackoverflow.com/questions/19568226/angular-js-rendering-svg-templates-in-directives\">Angular.js在指令渲染SVG模板,我在那里更换DOM节点模板时,与SVG节点的角度做。我得到的回答了我的一个反应,但我意识到,我失去了所有的数据绑定的角度。
请参阅Plunkr(点击更新): http://plnkr.co/edit/ HjOpqc?p = preVIEW
我如何更换SVG这些节点DOM节点,并留下我的角度绑定完好?我试着使用$编译,使其工作(就像我跟普通的HTML完成),但它只是不工作。
code:
VAR svgNS ='http://www.w3.org/2000/svg';
app.directive('路径',ngSvg('路径'));
app.directive('G',ngSvg('G'));函数ngSvg(类型){
返回函数($超时,$编译){
返回{
限制:'E',
链接:功能(范围,EL,ATTR){
//跳过的节点,如果他们已经SVG
如果(EL [0] .namespaceURI === svgNS){
返回;
} //我希望code的块下面的工作,
//但它不与NG-重复 //变种newAttr = {};
// _.each(EL [0] .attributes,功能(AT){
// newAttr [at.nodeName] = at.value;
//}); // VAR路径= makeNode(类型,萨尔瓦多,newAttr);
// VAR父= path.cloneNode(真); // $编译(父)(范围); //变种孩子= el.children();
// $(父).append(儿童); // $超时(函数(){
// el.replaceWith(父);
//})
//这个工程的渲染,但不更新SVG元素
//当点击更新
$超时(函数(){
变种newAttr = {};
_.each(EL [0] .attributes,功能(AT){
newAttr [at.nodeName] = at.value;
}); VAR路径= makeNode(类型,萨尔瓦多,newAttr);
VAR父= path.cloneNode(真);
变种孩子= el.children();
$(父).append(儿童);
el.replaceWith(父);
});
}
}
}
}/ *创建具有给定设置的形状节点。 * /
功能makeNode(名称,元素,设置){
// VAR NS ='http://www.w3.org/2000/svg';
VAR节点=与Document.createElementNS(svgNS,名);
对(在设置var属性){
VAR值=设置[属性]
如果(价值== NULL和放大器;!&安培;价值== NULL和放大器;!&安培;!attribute.match(/ \\ $ /)及和放大器;
(typeof运算值!=='串'||价值!=='')){
node.setAttribute(属性值);
}
}
返回节点;
}
此问题解决在1.3角,这里是与你所期望从角度指令的行为,一些自定义的SVG指令的实现。现在有一个特殊要求是指令的声明如下: templateNamespace:SVG
另请注意,我重写一些保留的属性,例如 X
中关于<$ C 高度
和$ C>&LT; RECT /&GT; 。为了对这些保留更多的控制,你可以利用 NG-ATTR
这样'&LT;矩形NG-ATTR-WIDTH ={{ngWidth}} /&GT;
的jsfiddle链接
下面是一个自定义&LT; RECT /&GT;
和&LT;圆/&GT;
app.directive('ngRect',[功能(){
返回{
templateNamespace:'SVG',
更换:真实,
模板:'&LT;矩形NG-ATTR-WIDTH ={{ngWidth}}NG-ATTR-HEIGHT ={{ngHeight}}NG-ATTR-X ={{NGX}}NG-ATTR-Y ={{NGY}}NG点击=ngRectClick()/&GT;,
范围: {
ngHeight':'=',
ngWidth':'='
},
链接:功能(范围,ELEM,ATTRS){
scope.ngRectClick =功能(){
的console.log(ELEM);
}
}
}
}]);app.directive('ngCircle',[功能(){
返回{
templateNamespace:'SVG',
更换:真实,
模板:'&LT;圈NG-ATTR-CX ={{ngCx}}NG-ATTR-CY ={{ngCy}}NG-ATTR-R ={{NGR}}NG-ATTR填充={{ngFill}}NG点击=ngCircleClick()/&GT;,
范围: {
ngCx':'=',
ngCy':'=',
NGR':'=',
ngFill':'='
},
链接:功能(范围,ELEM,ATTRS){
scope.ngCircleClick =功能(){
的console.log(ELEM);
}
}
}
}]);
A while ago I asked about "Angular.js rendering SVG templates in directives", where I was replacing the DOM nodes that angular makes when rendering templates, with SVG nodes. I got a response that answered it for me, but I realized that I lost all the databindings from angular.
See Plunkr (click update): http://plnkr.co/edit/HjOpqc?p=preview
How do I replace these DOM nodes with SVG nodes, and leave my angular bindings intact? I tried using $compile to make it work (as I've done with regular html), but its just not working.
code:
var svgNS = 'http://www.w3.org/2000/svg';
app.directive('path', ngSvg('path'));
app.directive('g', ngSvg('g'));
function ngSvg(type) {
return function($timeout, $compile) {
return {
restrict: 'E',
link: function(scope, el, attr) {
//skip nodes if they are already svg
if (el[0].namespaceURI === svgNS) {
return;
}
// I would expect the chunk of code below to work,
// but it does not with ng-repeat
// var newAttr = {};
// _.each(el[0].attributes, function(at) {
// newAttr[at.nodeName] = at.value;
// });
// var path = makeNode(type, el, newAttr);
// var parent = path.cloneNode(true);
// $compile(parent)(scope);
// var children = el.children();
// $(parent).append(children);
// $timeout(function() {
// el.replaceWith(parent);
// })
// this works for rendering, but does not update the svg elements
// when update is clicked
$timeout(function() {
var newAttr = {};
_.each(el[0].attributes, function(at) {
newAttr[at.nodeName] = at.value;
});
var path = makeNode(type, el, newAttr);
var parent = path.cloneNode(true);
var children = el.children();
$(parent).append(children);
el.replaceWith(parent);
});
}
}
}
}
/* Create a shape node with the given settings. */
function makeNode(name, element, settings) {
// var ns = 'http://www.w3.org/2000/svg';
var node = document.createElementNS(svgNS, name);
for (var attribute in settings) {
var value = settings[attribute];
if (value !== null && value !== null && !attribute.match(/\$/) &&
(typeof value !== 'string' || value !== '')) {
node.setAttribute(attribute, value);
}
}
return node;
}
This issue is solved in Angular 1.3 and here is an implementation of some custom svg directives with the behaviors you would expect from an Angular directive. There is now a special requirement is on the directive declaration as follows templateNamespace: 'svg'
Also notice I am overriding some reserved attributes, for example, x
and height
in regards to <rect/>
. To retain more control over these you can leverage ng-attr
as such '<rect ng-attr-width="{{ ngWidth }}" />
JSFiddle Link
Here is a custom <rect/>
and <circle/>
app.directive('ngRect', [function () {
return {
templateNamespace: 'svg',
replace: true,
template: '<rect ng-attr-width="{{ ngWidth }}" ng-attr-height="{{ ngHeight }}" ng-attr-x="{{ ngX }}" ng-attr-y="{{ ngY }}" ng-click="ngRectClick()"/>',
scope: {
'ngHeight': '=',
'ngWidth': '='
},
link: function (scope, elem, attrs) {
scope.ngRectClick = function() {
console.log(elem);
}
}
}
}]);
app.directive('ngCircle', [function () {
return {
templateNamespace: 'svg',
replace: true,
template: '<circle ng-attr-cx="{{ ngCx }}" ng-attr-cy="{{ ngCy }}" ng-attr-r="{{ ngR }}" ng-attr-fill="{{ ngFill }}" ng-click="ngCircleClick()"/>',
scope: {
'ngCx': '=',
'ngCy': '=',
'ngR': '=',
'ngFill': '='
},
link: function (scope, elem, attrs) {
scope.ngCircleClick = function() {
console.log(elem);
}
}
}
}]);
这篇关于在指令Angular.js更新SVG模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!