charlie
charlie

Reputation: 187

Update chart with new data not working

I'm drawing a bar chart with some initial data and then trying to update when a button is clicked. I get the error "Uncaught TypeError: Cannot read property 'length' of undefined". The error occurs after update buttom is clicked. How do I fix this and enable the update function to draw a new bar chart?

<div id="chart"></div>
<button id="update" onclick="update()">Update</button>

D3 code:

    var myData = [21, 3, 5, 21, 15];
    //Width and height
    var w = 250;
    var h = 250;
    var yScale = null;

    function draw(initialData) {
      var xScale = d3.scale.ordinal()
        .domain(d3.range(initialData.length))
        .rangeRoundBands([0, w], 0.05);

      yScale = d3.scale.linear()
        .domain([0, d3.max(initialData)])
        .range([0, h]);

      //Create SVG element
      var svg = d3.select("#chart")
        .append("svg")
        .attr("width", w)
        .attr("height", h);

      svg.selectAll("rect")
        .data(initialData)
        .enter()
        .append("rect")
        .attr("x", function(d, i) {
          return xScale(i);
        })
        .attr("y", function(d) {
          return h - yScale(d);
        })
        .attr("width", xScale.rangeBand())
        .attr("height", function(d) {
          return yScale(d);
        })
        .attr("fill", "steelblue");

      svg.selectAll("text")
        .data(initialData)
        .enter()
        .append("text")
        .text(function(d) {
          return d;
        })
        .attr("text-anchor", "middle")
        .attr("x", function(d, i) {
          return xScale(i) + xScale.rangeBand() / 2;
        })
        .attr("y", function(d) {
          return h - yScale(d) + 14;
        })
        .attr("font-family", "sans-serif")
        .attr("font-size", "11px")
        .attr("fill", "white");
    }

    draw(myData);

    var newData = [15, 5, 3, 15, 21];
    //update function
    function update(newData) {
      yScale.domain([0, d3.max(newData)]);

      var rects = d3.select("#chart svg")
        .selectAll("rect")
        .data(newData);

      // enter selection
      rects
        .enter().append("rect");

      // update selection
      rects
        .transition()
        .duration(300)
        .attr("y", function(d) {
          return h - yScale(d);
        })
        .attr("height", function(d) {
          return yScale(d);
        })

      // exit selection
      rects
        .exit().remove();

      var texts = d3.select("#chart svg")
        .selectAll("text")
        .data(newData);

      // enter selection
      texts
        .enter().append("rect");

      // update selection
      texts
        .transition()
        .duration(300)
        .attr("y", function(d) {
          return h - yScale(d) + 14;
        })
        .text(function(d) {
          return d;
        })

      // exit selection
      texts
        .exit().remove();
    }

Upvotes: 1

Views: 55

Answers (1)

Daniela Mogini
Daniela Mogini

Reputation: 539

The problem is that your update function expects an array of data as parameter but you call it without params. You can add button click listener using d3 like that.

d3.select("#update").on("click", function(){ update(newData); })

Created a fiddle for you

Upvotes: 1

Related Questions