Search code examples
ag-grid-angular

Cannot read property 'setRowData' of undefined / Issue with HTML template?


Am maintaining an AG-GRID re-usable template with all necessary methods (clear filer/ CSV download/ Autofit..etc options) --- Base Template. I have another AG-Grid template , which uses "Base Template" (thru dependency injection) and populate grid with a row of data based on searchString value. (Sample file below)

import { Component, OnInit, } from '@angular/core';
import { GridOptions, GridApi, } from "ag-grid-community";
import { ReportersgridComponent } from '../../commonpages/reportersgrid/reportersgrid.component'

@Component({
    selector: 'app-reporters',
    templateUrl: './reporters.component.html',
    styleUrls: ['./reporters.component.scss']
})
export class ReportersComponent implements OnInit {

    private reporterGrid: GridOptions;
    constructor(public reportersGrid: ReportersgridComponent, ) {
        this.reporterGrid = <GridOptions>{};
        this.reporterGrid.enableSorting = true;
        this.reporterGrid.enableFilter = true;
        this.reporterGrid.enableColResize = true;
        this.reporterGrid.columnDefs = this.reportersGrid.createColumnDefs();
        this.reporterGrid.rowData = this.reportersGrid.createRowData();
    }
    ngOnInit() {
    }
    //Search Function 
    performSearch() {
        let searchString = "";
        this.populateFiteredReporter(searchString);
        // this.reporterGrid.api.setRowData(reporterGrid.rowData)
    }
    populateFiteredReporter(searchString) {
        this.reporterGrid.rowData = [
            { fullName: 'fName,mName,lName2', address: "address2", country: "country2", postcode: "postcode2", phone: "phone", email: "email", qualification: "MBBS", institution: "institution", department: "department" },
        ];
        var str = JSON.stringify(this.reporterGrid.rowData);
        console.log('data:' + str);
        this.reporterGrid.api.setRowData(this.reporterGrid.rowData);

        //this.reportersGrid.populateFiteredReporter(searchString);
    }
}

In HTML of the above file, I am using "Base Template" s SELECTOR AS HTML TAG. (

<app-reportersgrid></app-reportersgrid>

) to display the grid portion.

Above gives error -> Cannot read property 'setRowData' of undefined.

Please note that if I replace Base Template's selector with base template's FULL HTML portion for ag-grid (which has (gridReady)="onGridReady($event)"), page works fine.

Can I get help to stick back to my original idea of keeping base template intact? (Note that all base template functions like export to csv, autofit etc works fine - those are coded in the base template along with OnGridReadty().)

Thanks in Advance.. ASJ.

22/10/2019 /* Template of reporters.component.html*/

<div>
  <div class="col-md-12">
    <div class="card">
      <div class="card-header text-uppercase  font-weight-bold">
        Search
      </div>
      <div class="card-body">
        <div>
          <div class="row">
            <div class="col-sm-4">
              <div class="form-group">
                <span>Name <i>(First/Middle/Last)</i></span>
                <input type="text" class="form-control" [(ngModel)]="reporterName">
              </div>
            </div>

          </div>    
        </div>
      </div>   
      <div class="card-footer">
        <div class="row">        
          <div class="col-6 col-sm-4 col-md-2 col-xl mb-3 mb-xl-0">
            <button type="button" class="btn btn-normal btn-primary" (click)="performSearch()" style="width: 100px; ">Search</button>

            <button type="button" class="btn btn-normal btn-light" style="width: 100px;">Reset</button>
          </div>


        </div>

      </div>
    </div>
  </div>
 <app-reportersgrid></app-reportersgrid>

</div>

Base template - HTML of the AG-GRID

 <div class="centered-content">

  <div>

    <ag-grid-angular #agGrid style="width: 100%; height: 358px;" class="ag-theme-balham"
      [gridOptions]="reporterGrid" [enableSorting]="true" enableFilter [sideBar]="sideBar"
      enableColResize [pagination]="true" [paginationPageSize]=10             
       rowDragManaged=true
      (gridReady)="onGridReady($event)">
      <ag-grid-column headerName="Name" field="fullName"></ag-grid-column>
      <ag-grid-column headerName="Address" field="address" [width]="150"></ag-grid-column>
      <ag-grid-column headerName="Country" field="country"></ag-grid-column>
      <ag-grid-column headerName="Postcode" field="postCode"></ag-grid-column>
      <ag-grid-column headerName="Phone" field="phone"></ag-grid-column>
      <ag-grid-column headerName="Email" field="email"></ag-grid-column>
      <ag-grid-column headerName="Qualification" field="qualification"></ag-grid-column>
      <ag-grid-column headerName="Institution" field="institution"></ag-grid-column>             
      <ag-grid-column headerName="Department" field="department" [cellRenderer]="countryCellRenderer">
      </ag-grid-column>
    </ag-grid-angular>

  </div>

</div>

/ReportersGridcomponent.ts file/

import { Component, OnInit } from '@angular/core';
//import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import {GridOptions, GridApi, Grid} from "ag-grid-community";

@Component({
  selector: 'app-reportersgrid',
  templateUrl: './reportersgrid.component.html',
  styleUrls: ['./reportersgrid.component.scss']
})
export class ReportersgridComponent implements OnInit {
  private reporterGrid: GridOptions;
  private gridApi:GridApi;
  private gridColumnApi;
  filterName: string | null;

  constructor( ) {
    this.reporterGrid = <GridOptions>{};
    this.reporterGrid.enableSorting = true;
    this.reporterGrid.enableFilter = true;
    this.reporterGrid.enableColResize = true;
    this.reporterGrid.columnDefs = this.createColumnDefs();
    this.reporterGrid.rowData = this.createRowData(); 
     }
  ngOnInit() {
  }
  createColumnDefs() {
    this.reporterGrid.columnDefs = [
     {
      headerName: "Name",
      field: "fullName", 
      width:100,      
  },
  {
    headerName: "Address",
    field: "address",
},

{
    headerName: "Country",
    field: "country",

},
{
  headerName: "Postcode",
  field: "postCode",
},
{
    headerName: "Phone",
    field: "phone",
},

{
    headerName: "Email",
    field: "email",
},
{
  headerName: "Qualification",
  field: "qualification",
},
{
    headerName: "Institution",
    field: "institution",
},
{
    headerName: "Department",
    field: "department",
}

  ];
return this.reporterGrid.columnDefs
  }
  createRowData(){
    this.reporterGrid.rowData = [
      //    {fullName: 'fName,mName,lName',address:"address1",country: "country",postcode: "postcode",phone: "phone",email:"email",qualification:"MBBS",institution:"institution",department:"department"},  
    ];
  return this.reporterGrid.rowData;
  }

  onGridReady(params) {
    this.gridApi = params.api;
    this.gridColumnApi = params.columnApi;
    this.autoSizeAll()
  }
  autoSizeAll() {
    var allColumnIds = [];
    this.gridColumnApi.getAllColumns().forEach(function(column) {
    allColumnIds.push(column.colId);
  });
    this.gridColumnApi.autoSizeColumns(allColumnIds);

}

onCSVExport() {

  this.reporterGrid.api.exportDataAsCsv();
 } 
 onSearchTextChange(newData: string) {
   this.reporterGrid.api.setQuickFilter(newData);
 }
 clearFilters() {
 if (this.gridApi.isQuickFilterPresent())
 {
   this.gridApi.setQuickFilter('');
   this.filterName="";
 }
 }

//  populateFiteredReporter(searchString){

//     this.reporterGrid.rowData = [
//       {fullName: 'fName,mName,lName2',address:"address2",country: "country2",postcode: "postcode2",phone: "phone",email:"email",qualification:"MBBS",institution:"institution",department:"department"},  
//   ];
//   var str= JSON.stringify(this.reporterGrid.rowData);
//   console.log('data:'+str);  
//   this.reporterGrid.api.setRowData(this.reporterGrid.rowData);
//   //return this.reporterGrid.rowData;
//   }
 }

Solution

  • The first thing you need to do is set your grid component to accept grid options from its parent:

    @Input() public reporterGrid: GridOptions;
    

    Here is an abbreviated version of what your grid component should look like. I suggest using properties or fields, instead of using methods to create your rows and columns. Just a suggestion.

    export class ReportersgridComponent implements OnInit {
        @Input() public reporterGrid: GridOptions;
        private columnDefs = [
            // put your column def json here
        ];
    
        private rowDefs = [
            // Put your row def json here
        ];
    
        constructor() {
        }
    
        ngOnInit() {
            this.reporterGrid.columnDefs = this.columnDefs;
            this.reporterGrid.rowData = this.rowDefs;
        }
    
        // rest of your file
    }
    

    And your reporters component ts file should look like this:

    export class ReportersComponent implements OnInit {
    
        private reporterGridOptions: GridOptions;
    
        constructor() {
            this.reporterGridOptions = {
                enableSorting: true,
                enableFilter: true,
                enableColResize: true,
            };
        }
    
        ngOnInit() {
        }
     // other code...
    }
    

    In your reporter component html, you need to pass in this value through the element like this:

    <app-reportersgrid [reporterGrid]="reporterGridOptions"></app-reportersgrid>
    

    Another suggestion, I would take some time to properly name things, adjust casing, and format your code so it is easier to read. I hope this helps get you heading in the right direction. Basically you want to pass your options object to the grid component, so it can have access to it.

    Also, you do not want to inject a component through a constructor. It will not be the same instance as the component in the template. Components are initialized and destroyed as they are rendered and removed from the view, and do not exist as singletons like services to.