Using ag-grid, how can I get the `api` attribute to not be null when working with angular 1.5 and directives?

2.3k views Asked by At

Disclaimer

First, I'd like to note I'm completely new to Angular so I am probably doing something wrong / dumb. I have finally come to the point where I'm not sure what else to try.

Context

I an working on a project where I need to have a grid that can contain nested or grouped columns. The site is also being built in AngularJS 1.5.9. One of the features of the grid is to be able to hide or show a set of columns in the grid based on user selections. Also, in using AngularJS I am trying to stick with directives as it makes the components a bit easier to use/re-use across the application. Also, in my opinion, it makes the code much more readable.

Problem / Question

Currently, when the user clicks the toggle checkbox on the template, the api attribute on the gridOptions object is undefined. As far as I can tell from the documentation on ag-grid says that this attribute should exist once the grid is bound. How do I get this to work properly without abandoning the directive? View the problem on Plunker

What I've tried

app.js

(function(){
  var app = angular.module('app', ['agGrid']);
  agGrid.initialiseAgGridWithAngular1(angular);

  app.directive('gridExample', function(){
    return {
      restrict: 'E',
      templateUrl:'sample-grid.html',
      controller: ['$scope', function($scope){
        // Objects
        $scope.options = {
          toggleColumn: true
        };
        // var ctrl = this;

        var rowData = [
          {col1: '1a', col2: '2a', col3: '3a'},
          {col1: '1b', col2: '2b', col3: '3b'},
          {col1: '1c', col2: '2c', col3: '3c'},
        ];

        // Methods
        $scope.loadData = function(){
          var columns = [];

          columns.push({headerName: "Col 1", field: "col1"});

          if ($scope.options.toggleColumn == true) {
            columns.push({headerName: "Col 2", field: "col2"});
          }

          columns.push({headerName: "Col 3", field: "col3"});

          $scope.gridOptions = {
            columnDefs: columns,
            rowData: rowData,
            angularCompileRows: false,
            enableColResize: true
          };
        };

        $scope.refreshGrid = function() {
          $scope.loadData();

          // HERE: I've tried this and $scope
          this.gridOptions.api.refreshView();
        };

        $scope.loadData();
      }]
    };
  });
})();

Template Markup

<label>
  <input type="checkbox"
         ng-model="options.toggleColumn"
         ng-click="refreshGrid()" />
         Toggle Col 2
</label>
<div ag-grid="gridOptions" class="ag-blue" style="height: 300px;"></div>
1

There are 1 answers

0
Sean Landsman On BEST ANSWER

The problem here is that you're replacing your initialised $scope.gridOptions in loadData the second time you call it.

A quick fix would be:

if ($scope.gridOptions) {
    $scope.gridOptions.api.setColumnDefs(columns)

} else {
    $scope.gridOptions = {
        columnDefs: columns,
        rowData: rowData,
        angularCompileRows: false,
        enableColResize: true
    };
}

This would set the gridOptions once, and the second time around just reuse it.

A better solution however would be to set the gridOptions outside of methods that are going to be called again.

In this case something like this would be a good starting point:

// Objects
$scope.options = {
    toggleColumn: true
};

var rowData = [
    {col1: '1a', col2: '2a', col3: '3a'},
    {col1: '1b', col2: '2b', col3: '3b'},
    {col1: '1c', col2: '2c', col3: '3c'},
];

$scope.gridOptions = {
    rowData: rowData,
    angularCompileRows: false,
    enableColResize: true,
    onGridReady: () => {
        $scope.loadData();
    }
};

// Methods
$scope.loadData = function () {
    var columns = [];

    columns.push({headerName: "Col 1", field: "col1"});

    if ($scope.options.toggleColumn == true) {
        columns.push({headerName: "Col 2", field: "col2"});
    }

    columns.push({headerName: "Col 3", field: "col3"});

    $scope.gridOptions.api.setColumnDefs(columns)

};

$scope.refreshGrid = function () {
    $scope.loadData();
    $scope.gridOptions.api.refreshView();
};

Now we set gridOptions outside of any method, which will ensure it doesn't get overwritten later. We also use the gridReady event to loadData once the grid is ready (other the api might not yet be available to you)