Himmel
Himmel

Reputation: 3709

Ng-repeat on directive creating duplicate DOM elements

I have directive that renders a d3 scatter-plot directive on the DOM. I also have an ng-bind bound to an array that lists the inputs provided for the given scatter-plot. Both of these elements, the scatterplot and inputs, are inside of a span with ng-repeat, like this:

<section>
    <h3>Saved Charts</h3>
        <div class="saved-charts-repeat" ng-repeat="s in savedCharts">
                <p ng-bind="s.input"></p>
                <scatter-template input="s.chart"></scatter-template>
        </div>
</section>

savedCharts, the array given to ng-repeat looks like this:

$scope.savedCharts = [
        {
            input: [[array], [array]], 
            chart: [{object}, {object}, {object}]
        },
        {
            input: [[array]], 
            chart: [{object}, {object}]
        }
 ];

s.input binds the array to the DOM, s.chart passes the chart objects to the scatter-template directive.

When I run this, the output looks like this: inputs repeating vertically, graph repeating horizontally

The 'GW's are the s.input arrays (each of them is 1 array), in this case.

They should be inline and going across the page. I inspected the element, and found that all of the charts were appearing in the first instance of the ng-repeat, and the s.inputs were being spread appropriately.

Look at the below from Chrome DevTools, the first instance of the wrapper, .saved-charts-repeat holds all of the charts, but only one of the inputs.

showing positioning of element with all of the graphs

Why are my inputs being spread out throughout the repeat, but my charts are being piled up in the first instance?

Edit

Here is my CSS

.saved-charts-repeat { //ngrepeat
  .inputs {
  }
  scatter-template {
    display: block;
  }
  svg {
    height: 300px;
    width: 300px;
    min-width: 320px;
  }

Edit 2

Here is a codepen that recreates my problem: http://codepen.io/himmel/pen/pJwMEE

Upvotes: 0

Views: 414

Answers (1)

Agop
Agop

Reputation: 1917

The problem is this line of code in your directive:

var svg = d3.select('scatter-template')

d3.select() returns the first element that matches the selector. In this case, it returns the first <scatter-template> element in your repeater, which is why all of your SVGs end up in the first <scatter-template> element.

What you want to do is this:

var svg = d3.select(el[0])

d3.select() can also take a direct instance of an element. Angular's link() function in your directive receives a jQuery-wrapped instance of the directive element, so we can pass the raw element to D3 via el[0].

Upvotes: 2

Related Questions