title: Google Visualization API number range controller sets low and high value to 0 when redrawing chart
body: <p>I'm using the Google Visualization API to plot some data on a site I'm building. On my actual site it's a very complicated arrangement of auto-generated plots and controls, but this problem is visible even with a very simple dashboard like that used in the API documentation demo. </p>
  
  <p>A <code>NumberRangeFilter</code> control is bound to a <code>Dashboard</code>. The control's lower slider handle (<code>lowValue</code>) is set to a value greater than the minimum, and the upper slider handle (<code>highValue</code>) is not changed from its default (i.e. is at the maximum). </p>
  
  <p>If the dashboard is redrawn using <code>dashboard.draw(data)</code>, the range filter control will reset its range to 0 (i.e. the low and high values are both at 0). This of course hides all of the data if none of the data points are 0.</p>
  
  <p>Here is a demonstration of the problem. Click <kbd>set slider range</kbd> or manually adjust the slider so that the low value is greater than 0, and the high value is unchanged. Then click <kbd>redraw chart</kbd>. You will see the slider readjust itself to the 0-0 range.</p>
  
  <p><div class="snippet" data-lang="js" data-hide="true">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>    // Load the Visualization API and the controls package.
        google.load('visualization', '1.0', {'packages':['controls']});
  
        // Set a callback to run when the Google Visualization API is loaded.
        google.setOnLoadCallback(drawDashboard);
  
        // Callback that creates and populates a data table,
        // instantiates a dashboard, a range slider and a pie chart,
        // passes in the data and draws it.
  
  var data;
  var dashboard;
  var donutRangeSlider;
  var colChart;
  
        function drawDashboard() {
  
          // Create our data table.
          data = google.visualization.arrayToDataTable([
            ['Name', 'Donuts eaten', 'Calories eaten (*100)'],
            ['Michael' , 5, 15],
            ['Elisa', 7, 30],
            ['Robert', 3, 10],
            ['John', 2, 70],
            ['Jessica', 6, 18],
            ['Aaron', 1, 2],
            ['Margareth', 8, 40]
          ]);
            
  
          // Create a dashboard.
          dashboard = new google.visualization.Dashboard(
              document.getElementById('dashboard_div'));
  
          // Create a range slider, passing some options
          donutRangeSlider = new google.visualization.ControlWrapper({
            'controlType': 'NumberRangeFilter',
            'containerId': 'filter_div',
            'options': {
              'filterColumnLabel': 'Donuts eaten',
                'minValue': 0
            }
          });
  
          // Create a column chart, passing some options
          colChart = new google.visualization.ChartWrapper({
            'chartType': 'ColumnChart',
            'containerId': 'chart_div',
            'options': {
              'width': 500,
              'height': 300,
              'legend': 'right'
            }
          });
  
          // Establish dependencies, declaring that 'filter' drives 'columnChart',
          // so that the pie chart will only display entries that are let through
          // given the chosen slider range.
          dashboard.bind(donutRangeSlider, colChart);
  
          // Draw the dashboard.
          dashboard.draw(data);
        }
  function setRange() {
      donutRangeSlider.setState({'lowValue': 1, 'highValue': 8});
      donutRangeSlider.draw();
  }
  
  function redrawDashboard() {
      dashboard.draw(data);
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script type='text/javascript' src="https://www.google.com/jsapi"&gt;&lt;/script&gt;
  
  &lt;p&gt;
  &lt;button onclick="setRange()"&gt;Set slider range&lt;/button&gt; 
    &lt;button onclick="redrawDashboard()"&gt;Redraw Dashboard&lt;/button&gt; 
  &lt;/p&gt;
  
  &lt;!--Div that will hold the dashboard--&gt;
      &lt;div id="dashboard_div"&gt;
        &lt;!--Divs that will hold each control and chart--&gt;
        &lt;div id="filter_div"&gt;&lt;/div&gt;
        &lt;div id="chart_div"&gt;&lt;/div&gt;
      &lt;/div&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>As far as I can tell, this is a straight-up bug in the API (and <a href="https://code.google.com/p/google-visualization-api-issues/issues/detail?id=1760" rel="nofollow">I have reported it</a> to the Google Visualization API's bug tracker), but perhaps I'm missing something. Is there a way to avoid this? If it is a bug in the API, is there any simple way to save the slider state before redrawing the dashboard, then restore it after redrawing the dashboard? </p>
  
  <hr>
  
  <p>I attempted to store the control state, redraw, then set an event listener to restore the control state after the redraw completes. However, this doesn't seem to quite work. If I manually store the control state, redraw, then restore the state after seeing the redraw complete, it works. However, when using the triggered event, the restored state doesn't stick. The "Redraw (workaround)" function does the following: </p>
  
  <ul>
  <li>Gets the current state of the control and saves it to a variable</li>
  <li>Sets a one-time event listener for the dashboard's <code>ready</code> event</li>
  <li>Redraws the dashboard</li>
  <li>The ready event then fires, and that function restores the control state and draws the control</li>
  <li>...the control state is not actually restored?</li>
  </ul>
  
  <p><div class="snippet" data-lang="js" data-hide="true">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>    // Load the Visualization API and the controls package.
        google.load('visualization', '1.1', {'packages':['controls']});
  
        // Set a callback to run when the Google Visualization API is loaded.
        google.setOnLoadCallback(drawDashboard);
  
        // Callback that creates and populates a data table,
        // instantiates a dashboard, a range slider and a pie chart,
        // passes in the data and draws it.
  
  var data;
  var dashboard;
  var donutRangeSlider;
  var colChart;
  
        function drawDashboard() {
  
          // Create our data table.
          data = google.visualization.arrayToDataTable([
            ['Name', 'Donuts eaten', 'Calories eaten'],
            ['Michael' , 5, 15],
            ['Elisa', 7, 30],
            ['Robert', 3, 10],
            ['John', 2, 70],
            ['Jessica', 6, 18],
            ['Aaron', 1, 2],
            ['Margareth', 8, 40]
          ]);
            
  
          // Create a dashboard.
          dashboard = new google.visualization.Dashboard(
              document.getElementById('dashboard_div'));
  
          // Create a range slider, passing some options
          donutRangeSlider = new google.visualization.ControlWrapper({
            'controlType': 'NumberRangeFilter',
            'containerId': 'filter_div',
            'options': {
              'filterColumnLabel': 'Donuts eaten',
                'minValue': 0
            }
          });
  
          // Create a pie chart, passing some options
          colChart = new google.visualization.ChartWrapper({
            'chartType': 'ColumnChart',
            'containerId': 'chart_div',
            'options': {
              'width': 500,
              'height': 300,
              'legend': 'right'
            }
          });
  
          // Establish dependencies, declaring that 'filter' drives 'colChart',
          // so that the pie chart will only display entries that are let through
          // given the chosen slider range.
          dashboard.bind(donutRangeSlider, colChart);
  
          // Draw the dashboard.
          dashboard.draw(data);
        }
  function setRange() {
      donutRangeSlider.setState({'lowValue': 1, 'highValue': 8});
      donutRangeSlider.draw();
  }
  
  function redrawDashboard() {
      dashboard.draw(data);
  }
  
  function alternateRedraw()     {
      console.log("Redrawing");
      var controlState = donutRangeSlider.getState();
      google.visualization.events.addOneTimeListener(dashboard,'ready',function(e){fixSlider(controlState)});
      dashboard.draw(data);
  }
  
  function fixSlider(state)     {
      console.log('Post draw event');
      donutRangeSlider.setState(state);
      donutRangeSlider.draw();
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script type='text/javascript' src="https://www.google.com/jsapi"&gt;&lt;/script&gt;
  &lt;p&gt;&lt;button onclick="setRange()"&gt;Set slider range&lt;/button&gt; &lt;br/&gt;
  
  &lt;button onclick="redrawDashboard()"&gt;Redraw Dashboard&lt;/button&gt;
  
  &lt;button onclick="alternateRedraw()"&gt;Redraw (workaround)&lt;/button&gt;
  &lt;/p&gt;
  &lt;!--Div that will hold the dashboard--&gt;
      &lt;div id="dashboard_div"&gt;
        &lt;!--Divs that will hold each control and chart--&gt;
        &lt;div id="filter_div"&gt;&lt;/div&gt;
        &lt;div id="chart_div"&gt;&lt;/div&gt;
      &lt;/div&gt;
    </code></pre>
  </div>
  </div>
  </p>