dinony
dinony

Reputation: 624

Add button to table chart (AngularJS/Google Charts)

I am trying to use the Table Charts component in an AngularJS 1.2.10 app.

I wrote a wrapper directive, which brings table chart into an AngularJS context.

    angular.module('my.charts.table', [])
        .directive('myTableChart', [function() {
            return {
                restrict : 'E',
                scope : {
                    columns : '=',
                    rows : '='
                },
                templateUrl : 'my.charts.table/myTableChart.tmpl.html',
                link : function(scope, element) {
                    var data = new google.visualization.DataTable();

                    // add columns

                    var table = new google.visualization.Table(element[0].childNodes[0]);

                    table.draw(data, { allowHtml : true }); 
                } 
           };
       }
  ]);

For given columns and rows the data table is initialized and drawn.

What I want to do is to add a column, which holds a button with AngularJS directives.

<button class="btn btn-primary" onclick="alert(\'Works\')" ng-click="testLog()">Test</button>

You can assume that the testLog() method is defined on the current scope.

The table chart component allows the direct insertion of HTML as cell values. However, this lies outside of the AngularJS lifecycle and, therefore, simply inserting the above HTML snippet won't work.

Now, I tried to compile and link the button manually.

var btn = $compile('<button class="btn btn-primary" onclick="alert(\'Works\')" ng-click="testLog()">Test</button>')(scope);

I can append the button manually.

element.append(btn);

However, the table chart expects HTML, not a DOM element. If I pass btn[0].outerHTML, the ngClick directive won't trigger.

Is there a way to solve this problem?

Here is the complete code snippet:

google.load('visualization', '1', {
  packages: ['corechart', 'table']
});

google.setOnLoadCallback(function() {
  angular.bootstrap(document, ['my.app']);
});

angular.module('my.app', [])
  .directive('myTableChart', function() {
    return {
      restrict: 'E',
      scope: {
        columns: '=',
        rows: '='
      },
      template: '<div></div>',
      link: function(scope, element) {
        var data = new google.visualization.DataTable();

        for (var i = 0; i < scope.columns.length; i++) {
          data.addColumn(scope.columns[i].type, scope.columns[i].name);
        }

        data.addRows(scope.rows);

        var table = new google.visualization.Table(element[0].childNodes[0]);
        table.draw(data, {
          width: '100%',
          allowHtml: true
        });
      }
    };
  })
  .directive('myTestTable', ['$compile',
    function($compile) {
      return {
        restrict: 'E',
        scope: {},
        template: '<my-table-chart ng-if="curRows != null" columns="curCols" rows="curRows"></my-table-chart>',
        link: function(scope, element) {
          scope.curCols = [{
            type: 'string',
            name: 'Test'
          }, {
            type: 'string',
            name: ''
          }];

          scope.curRows = [];

          scope.testLog = function() {
            alert('Works too');
          };

          var btn = $compile('<button class="btn btn-primary" onclick="alert(\'Works\')" ng-click="testLog()">Test</button>')(scope);

          var btnHtml = btn[0].outerHTML;

          element.append(btn);

          scope.curRows.push(['test entry', btnHtml]);
        }
      };
    }
  ]);
<my-test-table></my-test-table>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>

<script src="https://www.google.com/jsapi"></script>

Upvotes: 0

Views: 1136

Answers (1)

Vadim Gremyachev
Vadim Gremyachev

Reputation: 59328

Better late than never, the following solution allows to trigger testLog event via ng-click directive:

  • since Google Chart google.visualization.Table does not support adding DOM elements, move compilation from myTestTable to myTableChart
  • to access testLog function from myTableChart directive scope, change the declaration to ng-click="$parent.testLog()"
  • perform compilation once the chart is rendered:

    google.visualization.events.addListener(table, 'ready', function() {
        var table_div = table.getContainer();
        $compile(table_div)(scope); 
    });  
    

Example

google.load('visualization', '1', {
  packages: ['corechart', 'table']
});

google.setOnLoadCallback(function() {
  angular.bootstrap(document, ['my.app']);
});

angular.module('my.app', [])
  .directive('myTableChart', function($compile) {
    return {
      restrict: 'E',
      scope: {
        columns: '=',
        rows: '='
      },
      template: '<div></div>',
      link: function(scope, element) {
        var data = new google.visualization.DataTable();

        for (var i = 0; i < scope.columns.length; i++) {
          data.addColumn(scope.columns[i].type, scope.columns[i].name);
        }

        data.addRows(scope.rows);

        var table = new google.visualization.Table(element[0].childNodes[0]);
        google.visualization.events.addListener(table, 'ready', function() {
            var table_div = table.getContainer();
            $compile(table_div)(scope); 
        });  

        table.draw(data, {
          width: '100%',
          allowHtml: true
        });
      }
    };
  })
  .directive('myTestTable', ['$compile',
    function($compile) {
      return {
        restrict: 'E',
        scope: {},
        template: '<my-table-chart ng-if="curRows != null" columns="curCols" rows="curRows"></my-table-chart>',
        link: function(scope, element) {
          scope.curCols = [{
            type: 'string',
            name: 'Test'
          }, {
            type: 'string',
            name: ''
          }];

          scope.curRows = [];

          scope.testLog = function() {
            alert('Works too');
          };

          var btnHtml = '<button class="btn btn-primary" onclick="alert(\'Works\')" ng-click="$parent.testLog()">Test</button>';
          scope.curRows.push(['test entry', btnHtml]);
        }
      };
    }
  ]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<script src="https://www.google.com/jsapi"></script>

<my-test-table></my-test-table>

Upvotes: 1

Related Questions