Our blazing fast Grid component built with pure JavaScript


Post by JussiSa »

I'm trying to make an own wrapper component around Bryntum grid but I get a following error:

ERROR TypeError: can't access property "element", _0x247514 is undefined

This comes from new Grid() initialization.

Steps taken:

  • Create a wrapper component (code below)

import { Component, ElementRef, OnInit } from '@angular/core';
import { Grid } from 'bryntum-grid';

@Component({
    selector: 'bryntum-grid',
    template: '',
    styleUrls: ['./bryntum-grid.component.scss'],
})
export class BryntumGridComponent implements OnInit {
    private grid: any;

constructor(private elementRef: ElementRef) {}

ngOnInit(): void {
    this.grid = new Grid({
        adopt: this.elementRef.nativeElement,
    });
}
}

Also tried to use a Div element (using @ViewChild) instead of ElementRef.nativeElement for adopt-property without any luck. The wrapper component provided by Bryntum caused the same error to show up.


Post by saki »

We have this constructor in our wrapper:

    constructor(element: ElementRef) {
        // Needed later, used as target when rendering Bryntum Grid
        this.elementRef = element;
    }

Try it please.

If that does not help, post please a showcase that we can run, investigate and debug.


Post by JussiSa »

No luck. Still getting the same error.

Tried to implement the full wrapper from examples, full code below:

import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { Grid, Store } from 'bryntum-grid';

const featureInputs = [
    'cellEdit',
    'cellMenu',
    'cellTooltip',
    'columnDragToolbar',
    'columnPicker',
    'columnReorder',
    'columnResize',
    'filter',
    'filterBar',
    'group',
    'groupSummary',
    'headerMenu',
    'quickFind',
    'regionResize',
    'search',
    'sort',
    'stripe',
    'summary',
    'tree',
];

const configInputs = [
    'autoHeight',
    'columns',
    'data',
    'emptyText',
    'enableTextSelection',
    'readOnly',
    'rowHeight',
    'store',
];

@Component({
    selector: 'bryntum-grid',
    template: '',
    styleUrls: ['./bryntum-grid.component.scss'],
})
export class BryntumGridComponent implements OnInit, OnChanges {
    private gridInstance: Grid;

private elementRef: ElementRef;

// Configs
@Input() autoHeight: boolean;
@Input() columns: object[];
@Input() data: object[];
@Input() emptyText: string;
@Input() enableTextSelection: boolean;
@Input() readOnly: boolean;
@Input() rowHeight: number;
@Input() store: object;

// Features, only used for initialization
@Input() cellEdit: boolean;
@Input() cellMenu: boolean | object;
@Input() cellTooltip: boolean | object;
@Input() columnDragToolbar: boolean;
@Input() columnPicker: boolean;
@Input() columnReorder: boolean;
@Input() columnResize: boolean;
@Input() filter: boolean | object;
@Input() filterBar: boolean | object;
@Input() group: boolean | object | string;
@Input() groupSummary: boolean;
@Input() headerMenu: boolean | object;
@Input() quickFind: boolean;
@Input() regionResize: boolean;
@Input() search: boolean;
@Input() sort: boolean | string | object[];
@Input() stripe: boolean;
@Input() summary: boolean;
@Input() tree: boolean;

@Output() selectedRecord: object = null;
@Output() onGridEvents = new EventEmitter<object>();

constructor(private element: ElementRef) {
    this.elementRef = element;
}

ngOnInit(): void {
    const // Features config object
        featureConfig = {},
        // Grid config object
        config = {
            // Use this element as our encapsulating element
            adopt: this.elementRef.nativeElement,

            // Listeners, will relay events
            listeners: {
                catchAll(event) {
                    if (event.type === 'selectionchange') {
                        this.selectedRecord = this.gridInstance.selectedRecord;
                    }

                    this.onGridEvents.emit(event);
                },

                thisObj: this,
            },

            features: featureConfig,
        };

    //Pass configs on to grid
    configInputs.forEach(configName => {
        if (configName in this) {
            config[configName] = this[configName];
        }
    });

    // Pass feature configs on to grid
    featureInputs.forEach(featureName => {
        if (featureName in this) {
            featureConfig[featureName] = this[featureName];
        }
    });

    this.gridInstance = new Grid(config);
}

ngOnChanges(changes: SimpleChanges) {
    if (this.gridInstance) {
        // Iterate over all changes
        Object.entries(changes).forEach(([name, { currentValue }]) => {
            // Apply changes that match configs to grid
            if (configInputs.includes(name)) {
                this.gridInstance[name] = currentValue;
            }
        });
    }
}

addRow(data): object {
    // Add a row using the supplied data
    return (this.gridInstance.store as Store).add(data);
}

removeRow() {
    // Remove selected row (if any)
    this.gridInstance.selectedRecord && this.gridInstance.selectedRecord.remove();
}
}

Post by saki »

I see. Post please the full app (w/o node_modules) so that we can find the culprit.


Post by JussiSa »

Got it to work now. It had to have data and columns set in time for initializing, so now I init it only after the wrapper component gets some data.


Post Reply