Search code examples
javascriptangularjsd3.jssvgangularjs-ng-click

ng-click not working in D3 generated svg


I'm using D3 with Angular and I want to insert some text elements into my svg and have an ng-click on them to fire off some functions in my controller. However it seems the ng-click never even fires. I've tried using $compile as suggested in the following posts:

neither of those solutions work for me. it does appear the $compile is doing something because it appends the attributes role="button" and tabindex="0" to my element like so:

Before $compile:

<svg>
   <text y="30" cursor="pointer" ng-click="alert('clicked')">CLICK ME</text>
</svg>

After $compile:

<svg>
   <text y="30" cursor="pointer" ng-click="alert('clicked')" role="button" tabindex="0">CLICK ME</text>
</svg>

I'm wondering if something on the page may be stealing the click event? it seems that angular has added a click handler the the root html element. I have never noticed this before

enter image description here

This is the directive code I have

.directive('clickMe', function ($compile) {
  return {
    restrict: 'A',
    link: function (scope, element, attributes) {
      var svg = d3.select(element[0])
        .append('svg');
        svg.append('text')
          .text('CLICK ME')
          .attr('y', '30')
          .attr('cursor', 'pointer')
          .attr('ng-click', 'alert(\'clicked\')');

      var compiledSvg = $compile(svg.node())(scope);
      element[0].children[0].replaceWith(compiledSvg[0]);
})

A jsfiddle with the versions of D3 and Angular I'm using which illustrates the problem: https://jsfiddle.net/soultrip/604pts5v/3/


Solution

  • I don't think that alert is in scope inside your template. Instead, create a method in your directive scope and call that on ngClick.

    var myApp = angular.module('myApp', []);
    
    myApp.directive('myDirective', function($compile) {
      return {
        restrict: 'A',
        link: function(scope, element, attributes) {
          let svg = d3.select(element[0])
            .append('svg');
          svg.append('text')
            .text('CLICK ME')
            .attr('y', '30')
            .attr('cursor', 'pointer')
            .attr('ng-click', 'showAlert(\'clicked\')');
          let compiledSvg = $compile(svg.node())(scope);
          element[0].children[0].replaceWith(compiledSvg[0]);
    
          scope.showAlert = function(message) {
            alert(message);
          };
        }
      }
    });
    

    https://jsfiddle.net/604pts5v/5/