2015-05-05 4 views
5

Sto provando a creare un grafico d3 usando una direttiva Angolare. Riesco a crearlo, ma il problema è che voglio degli eventi con ng-clic sugli elementi del grafico e non sono sicuro di come dovrebbe essere fatto.Angolare ng-click all'interno di un grafico d3 creato dinamicamente non funziona

Qui è la mia direttiva:

.directive('circleChart', function($parse, $window, $compile) { 
     return { 
      restrict: 'A', 
      scope: { 
       datajson: '=' 
      }, 
      link: function(scope, elem, attrs) { 

       var circleChart = new CircleChart(scope.datajson); 
       circleChart.initialise(scope); 
       var svg = circleChart.generateGraph(); 
       svg = angular.element(svg); 

       console.log(svg); 
       //scope.$apply(function() { 
        var content = $compile(svg)(scope); 
        elem.append(content); 
       //}); 
      } 
     } 
    }); 

L'oggetto CircleChart crea mia tabella d3 e c'è il posto allego un attributo ng-click agli elementi del grafico (non sembra essere un modo angolare corretta di farlo):

var CircleChart = Class.create({ 
    initialise: function(scope) { 
     this.datajson = scope.datajson; 
    }, 

    generateGraph: function() { 

    ............. 

    var chartContent = d3.select("div#chart-content"); 

    var svg = chartContent.append("svg") 
     .attr("id", "circle") 
     .attr("width", diameter) 
     .attr("height", diameter) 
     .style("border-radius", "50px") 
     .append("g") 
     .attr("transform", "translate(" + diameter/2 + "," + diameter/2 + ")"); 

     ............... 

      var circle = svg.selectAll("circle") 
       .data(nodes) 
       .enter().append("circle") 
       .attr("class", function(d) { 
        return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; 
       }) 
       .attr("id", function(d) { 
        return d.id; 
       }) 
       .attr("value", function(d) { 
        return d.name 
       }) 
       .attr("parent", function(d) { 
        if (d.parent) return d.parent['id'] 
       }) 
       .attr("ng-click", function(d) { 
        return "getEgs('" + d.id + "')"; 
       }) 

    ............... 

il codice d3 sta lavorando bene, perché se tolgo il codice di compilazione dalla direttiva, il grafico viene disegnato, ma i NG-click non sparano.

Se lascio il codice di compilazione lì, entra in un ciclo infinito e il browser sta accumulando memoria finché non devo ucciderlo.

Ovviamente, il mio metodo non funziona e sarà impressionante se qualcuno mi può aiutare

+0

Che cos'è il 'svg' nella funzione' generateGraph'? Questo DOM è staccato? Inoltre, a mio parere, non è una buona idea generare modelli angolari dal codice. Il modo in cui lo farei è passare i callback a 'CircleChart' durante l'inizializzazione o durante l'invocazione, catturare l'evento click in d3 e richiamare tale callback tramite codice Javascript. –

+0

@musically_ut Ho aggiornato la mia domanda con il codice di creazione svg. Sto cercando di capire cosa hai detto sul passaggio dei callback. Ti stai riferendo alla funzione reale che voglio chiamare con il ng-click? Posso probabilmente accedervi se utilizzo l'ambito del controller nella mia direttiva. –

+0

Sì, preferisco chiamare la funzione 'getEgs' all'interno di' .on ('click', ...) 'invece di emettere un' ng-click' nel codice. –

risposta

5

Dal momento che si sta modificando il DOM dall'interno del CircleChart.generateGraph e ri-aggiungendo i contenuti dell'elemento in voi DIRETTIVA: elem.append(content) dopo la compilazione, tu (probabilmente) finisci in un ciclo infinito.

Se si vuole compilare il modello così prodotto, è possibile semplice chiamata $compile(elem.contents())(scope); senza dover clear e append nuovo il contenuto. $compile funzionerà con la magia angolare sul DOM sul posto.


Tuttavia, come ho suggerito nei commenti, in quanto si ha accesso a tutto il settore in CircleChart (che a mio parere è probabilmente un peso inutile), si dovrebbe catturare l'evento click in d3 e richiamare la funzione getErgs dal codice anziché $compile -ingendo il codice e delegando l'attività a Angular.

+2

Grazie per la tua risposta, sono riuscito a farlo funzionare ora. Quello che ho fatto è stato accedere al mio controller nel controller 'direttiva: 'egCtrl'', quindi invece di posizionare' getEgs() 'sul' $ scope' del controller, lo aggiungo come un attributo simile a: 'this.getEgs = function() {} '. Quindi, come hai detto, uso 'd 'di d3 (' click ', ...)'. –

Problemi correlati