TypeScript/NG2 with dhtmlxGrid

Hello everyone,

I wanted to start this topic so that we can all share our experiences with using dhtmlxGrid in our Angular 2 applications. Unfortunately, DHTMLX does not plan to release type definitions and full TypeScript support until 2017. This shouldn’t come as a surprise because the full library contains more than 60k lines of code. I would imagine that it will take some time for them to release a stable solution.

With that said, I believe that it is still feasible to use DHTMLX with Angular 2. In fact, I was able to successfully render a dhtmlxGrid with TypeScript & Angular 2. The current issue that I am stuck on is with custom column types. If anyone has potential solutions or advice that they could share with me, it would be much appreciated!

In my particular case, I was able to get the dhtmlxGrid working by doing the following:

1) Dependency injection on index.html, such that: 
<script src="app/dhtmlx/dhtmlx.js" type="text/javascript"></script>

2) Declare your dhtmlXGridObject as type any
import { Component} from '@angular/core';
declare var dhtmlXGridObject: any;

3) Your component should look something like this:
@Component({
    selector: 'ids-dhtmlx',
    templateUrl: 'app/dhtmlx/dhtmlx.component.html'
})

export class DataHtmlComponent {
    private mygrid: any;
    private numRows: number;
    private numColumns: number;
    private numTables: number;
    private rowsPerPage: number;
    private data: any[];
    private colDef: any[];
    private colWidth: any[];
    private colAlign: any[];
    private colTypes: any[];
    private colNames: any[];
    private eXcell_details: any;
    private showStyle: boolean = false;

    constructor() {
        this.numRows = 20;
        this.numTables = 1;
        this.rowsPerPage = 10;
        this.colNames = [
            'year', 'toyota', 'gm', 'vw', 'ford', 'hyundai', 'honda', 'tesla', 'bmw', 'mercedes', 'lamborgini',
            'year1', 'toyota1', 'gm1', 'vw1', 'ford1', 'hyundai1', 'honda1', 'tesla1', 'bmw1', 'mercedes1',
            'lamborgini1',
            'year2', 'toyota2', 'gm2', 'vw2', 'ford2', 'hyundai2', 'honda2', 'tesla2', 'bmw2', 'mercedes2',
            'lamborgini2',
            'year3', 'toyota3', 'gm3', 'vw3', 'ford3', 'hyundai3', 'honda3', 'tesla3', 'bmw3', 'mercedes3',
            'lamborgini3',
            'year4', 'toyota4', 'gm4', 'vw4', 'ford4', 'hyundai4', 'honda4', 'tesla4', 'bmw4', 'mercedes4',
            'lamborgini4', 'sparkline'
        ];
        this.data = [];
        this.colDef = [];
        this.colWidth = [];
        this.colAlign = [];
        this.colTypes = [];
        this.numColumns = this.colNames.length;
        this.createColumnDef();
        this.createData();
        //this.eXcell_details = new eXcell_details();
    }

    ngAfterContentInit() {
        for (let i = 1; i < this.numTables + 1; i++) {
            const start = new Date().getTime();
            const mygrid = new dhtmlXGridObject('gridbox');
            mygrid.setHeader(this.colNames.join(','));
            mygrid.setInitWidths(this.colWidth.join(','));
            mygrid.setColAlign(this.colAlign.join(','));
            mygrid.setColTypes(this.colTypes.join(','));
            mygrid.setColSorting(this.colDef.join(','));
            const rowCount = 0;
            mygrid.init();
            mygrid.enableSmartRendering(true);
            mygrid.parse(this.data, 'jsarray');
        }
    }

    getStyle() {
        if (this.showStyle) {
            return 'yellow';
        } else {
            return '';
        }
    }

    private createData() {
        for (let j = 0; j < this.numRows; j++) {
            const time = new Date(new Date().getTime() + (j * (24 * 60 * 60 * 1000)));
            const valObj: any[] = [];
            for (let i = 0; i < this.numColumns; i++) {
                const val = Math.floor(Math.random() * (7710000 - 1710000) + 1710000);
                valObj.push(`${val}`);
            }
            this.data.push(valObj);
        }
    }

    private createColumnDef() {
        for (let i = 0; i < this.colNames.length; i++) {
            this.colDef.push('int');
            this.colWidth.push(100);
            this.colAlign.push('left');
            this.colTypes.push('edn');
        }
        this.colTypes[this.colTypes.length - 1] = 'details';
    }
}

The key thing to note here is that most of the work is being done in the ngAfterContentInit lifecycle hook. dhtmlxGrid kicks off by looking for the ‘gridbox’ ID. If we do this in the constructor, the DOM will not render in time for dhtmlxGridObject and therefore return an error, likely to be ‘Cannot set innerHtml of null’.

That’s all that I have for now but I’m hoping to get over this issue with custom column types. Ideally, I would like to insert a column with rows of custom visualizations, like a line or bar chart. If you guys have any suggestions, I’m certainly open to hearing and trying them out!

-Rich

Solution:
Instead of extending the eXcell_details’s prototype to the eXcell object, you could get this working by assigning the eXcell_details function to the window object. Such that window[‘eXcell_details’] = eXcell_details. I did this in the constructor…