简体   繁体   English

Angular.js在指令中更新SVG模板

[英]Angular.js updating SVG templates in directives

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. 前一段时间我问过“ Angular.js在指令中渲染SVG模板 ”,我用SVG节点替换渲染模板时角度所产生的DOM节点。 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 请参阅Plunkr(单击更新): http ://plnkr.co/edit/HjOpqc?p = preview

How do I replace these DOM nodes with SVG nodes, and leave my angular bindings intact? 如何用SVG节点替换这些DOM节点,并保持我的角度绑定完整? I tried using $compile to make it work (as I've done with regular html), but its just not working. 我尝试使用$ compile使其工作(因为我已经使用常规html),但它只是不工作。

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. 这个问题在Angular 1.3中得到了解决,这里是一些自定义svg指令的实现,它们具有您期望从Angular指令获得的行为。 There is now a special requirement is on the directive declaration as follows templateNamespace: 'svg' 现在有一个特殊要求是指令声明如下templateNamespace: 'svg'

Also notice I am overriding some reserved attributes, for example, x and height in regards to <rect/> . 另请注意,我正在覆盖一些保留属性,例如xheight<rect/> To retain more control over these you can leverage ng-attr as such '<rect ng-attr-width="{{ ngWidth }}" /> 为了保持对这些控制的更多控制,你可以利用ng-attr这样的'<rect ng-attr-width="{{ ngWidth }}" />

JSFiddle Link JSFiddle链接

Here is a custom <rect/> and <circle/> 这是一个自定义的<rect/><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);
            }
        }
    }
}]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM