Search code examples
javascriptknockout.jsgoogle-visualizationcustom-binding

GoogleCharts with KnockoutJS custom binding only draws first chart but not the rest


I have been looking for a solution to this problem but could not find anywhere. Therefore I am requesting you guys here.

I am trying to bind GoogleBarChart with KnockoutJS model view. All Binding events get called perfectly fine, but somehow it only draws the first chart.

Binding is as follow:

// View Model 1
function ViewModel1() {    
    var self = this;
    self.ViewModel1_BarData =  ko.computed(function () {
         
        return new google.visualization.arrayToDataTable([
          ['EmailAddress', 'Received'],
          ['[email protected]', 12],
          ['[email protected]', 20],
          ['[email protected]', 15]
		  ]);
    });
  
  
  // View Model 2
function ViewModel2() {    
    var self = this;
    self.ViewModel2_BarData =  ko.computed(function () {
         
        return new google.visualization.arrayToDataTable([
          ['Server', 'Occupied Space'],
          ['server1', 10],
          ['server2', 20],
          ['server3', 40]
		  ]);
    });
  
  
  
// Knockout Custom Binding for googleBarChart
  
ko.bindingHandlers.googleBarChart = {
    init: function (element, valueAccessor, allBindingsAccesor, viewModel, bindingContext) {
        var chart = new google.charts.Bar(element);
        ko.utils.domData.set(element, 'googleBarChart', chart);
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var value = ko.unwrap(valueAccessor());
        var options = allBindings.get('chartOptions') || {};        
        options = ko.unwrap(options);
      
        var chart = ko.utils.domData.get(element,'googleBarChart');
        chart.draw(value, options);
    }
};
<!-- First Chart -->
<div id="ViewModel1Bindng_div">
  
  <div id="ViewModel1_bar_div" data-bind="googleBarChart: ViewModel1_BarData, chartOptions: {
    width: 400, legend: { position: 'none' }, chart: { title: 'title-text', subtitle: 'subtitle-text' }}"></div>
  
</div>

<!-- Second Chart -->

<div id="ViewModel2Binding_div">
 
  <div id="ViewModel2_bar_div" data-bind="googleBarChart: ViewModel2_BarData, chartOptions: {
    width: 400,legend: { position: 'none' }, chart: { title: 'title-text', subtitle: 'subtitle-text' }}">
   </div>
</div>

Any help would be appreciated. Thanks in advance. Regards, Rohail


Solution

  • You have misspelled the element id here:

    ko.applyBindings(ViewModel2_model , document.getElementById("ViewModel2Bindng_div"))
    

    It should be:

    ko.applyBindings(ViewModel2_model , document.getElementById("ViewModel2Binding_div"))
    

    I have updated your snippet to work.

    // View Model 1
    function ViewModel1() {
      var self = this;
      self.ViewModel1_BarData = ko.computed(function() {
    
        return new google.visualization.arrayToDataTable([
          ['EmailAddress', 'Received'],
          ['[email protected]', 12],
          ['[email protected]', 20],
          ['[email protected]', 15]
        ]);
      });
    }
    
    // View Model 2
    function ViewModel2() {
      var self = this;
      self.ViewModel2_BarData = ko.computed(function() {
    
        return new google.visualization.arrayToDataTable([
          ['Server', 'Occupied Space'],
          ['server1', 10],
          ['server2', 20],
          ['server3', 40]
        ]);
      });
    }
    
    
    // Knockout Custom Binding for googleBarChart
    
    ko.bindingHandlers.googleBarChart = {
      init: function(element, valueAccessor, allBindingsAccesor, viewModel, bindingContext) {
        var chart = new google.visualization.BarChart(element);
        ko.utils.domData.set(element, 'googleBarChart', chart);
      },
      update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var value = ko.unwrap(valueAccessor());
        var options = allBindings.get('chartOptions') || {};
        options = ko.unwrap(options);
    
        var chart = ko.utils.domData.get(element, 'googleBarChart');
        chart.draw(value, options);
      }
    };
    
    
    var ViewModel1_model = new ViewModel1();
    ko.applyBindings(ViewModel1_model, document.getElementById("ViewModel1Bindng_div"));
    
    
    var ViewModel2_model = new ViewModel2();
    ko.applyBindings(ViewModel2_model, document.getElementById("ViewModel2Binding_div"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
    <script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['corechart'],'language':'en'}]}">
    </script>
    
    <!-- First Chart -->
    <div id="ViewModel1Bindng_div">
    
      <div id="ViewModel1_bar_div" data-bind="googleBarChart: ViewModel1_BarData, chartOptions: {
        width: 400, legend: { position: 'none' }, chart: { title: 'title-text', subtitle: 'subtitle-text' }}"></div>
    
    </div>
    
    <!-- Second Chart -->
    
    <div id="ViewModel2Binding_div">
    
      <div id="ViewModel2_bar_div" data-bind="googleBarChart: ViewModel2_BarData, chartOptions: {
        width: 400,legend: { position: 'none' }, chart: { title: 'title-text', subtitle: 'subtitle-text' }}">
      </div>
    </div>