Generic FlexGrid with CellFactory

Posted by: pascal.hanel on 13 September 2020, 6:51 pm EST

  • Posted 13 September 2020, 6:51 pm EST

    Hi all,

    I am currently working on a quite complex Angular 10 application with many FlexGrids, which should be generated from some meta information coming from the backend. This means, the cells of the grid should display ComboBoxes, Autosuggestions, depending on the meta data coming from the backend.

    I have implemented all of this with ng-templates (+ wjFlexGridCellTemplate) and inside of those ng-templates I used ng-containers with ngSwitch to select the right template depending on the meta data (if it should be a dropdown, autosuggestion and so on...)

    Unfortunately, rendering takes quite some time with those complex checks inside of the ng-template. Therefore I started using a CustomCellFactory for my requirement.

    This is how my updateCell function looks like:

    public updateCell(p: GridPanel, r: number, c: number, cell: HTMLElement, rng?: CellRange, updateContent?: boolean) {
    switch (p.cellType) {
    // regular cells
    case CellType.Cell:
    // get cell geometry
    super.updateCell(p, r, c, cell, rng, false);

    switch (dataType) {
    case 'dropDown':
    this.createGenericDropdown(p, r, c, cell);
    break;

    case 'string':
    this.createDefaultCell(p, r, c, cell);
    break;

    default:
    break;
    }

    break;

    ...
    }
    }


    And then for example, creating the generic Dropdowns:

    public createGenericDropdown(panel: GridPanel, rowIdx: number, colIdx: number, cell: HTMLElement): void {
    const supplierId = this.headerDefinitions[colIdx].supplierId;
    const itemsSource = panel.grid.itemsSource;
    const combo = new ComboBox(document.createElement('div'), {
    displayMemberPath: 'name',
    selectedValuePath: 'name',
    selectedValue: itemsSource[rowIdx].map[supplierId],
    itemsSource: itemsSource[rowIdx].propertyMeta[supplierId].dropDownValues
    });
    cell.innerHTML = '';
    cell.appendChild(combo.hostElement);
    panel.rows[rowIdx].height = 36;
    }


    The rendering already seems to be a bit faster, but now I am a bit stuck with handling the editing of the grid. In the ng-templates I used the (lostFocus) event to trigger some save action. And again, depending on some further meta information I had to use different save actions in the component where I have implemented the FlexGrid.

    Now coming to my questions:

    1. How can I bind a function from the ComboBox lostFocus event inside of another component?
    2. Instead of using a ComboBox, I would prefer using a DataMap. But I noticed that binding a DataMap to a Column in the updateCell function is causing a re-rendering loop of the cell.

    Do you have any other examples of more extended CellFactory usage than the demo for the CustomCellFactory?

    As it doesn't even show how the editing works with custom cell factories, it is a bit too basic in my opinion.

    Thank you
    Pascal

  • Replied 14 September 2020, 3:12 pm EST

    Hi Pascal,

    We are sorry but we do not have any sample that demonstrates how to bind input controls to FlexGrid using CellFactory. The CellFactory is used for customizing the cells in the FlexGrid only and is rarely used for adding custom editors in the FlexGrid.

    Regarding the lostFocus event, we understand that you were using the lostFocus event in the cell template to save the values but can you let us know how you added the event handler for this event in a different component. Were you using the EventEmitter object?

    Since you need to add the handler in a different component, you will need to get the reference of the ComboBox or other controls in the component. You can use the static getControl method of the Control class:
    public addSaveHandler(grid, row, col) {
    // get the cell element
    var cell = grid.cells.getCellElement(row, col);
    // a cell will only be created if it is actually displayed on the DOM
    // if it is not displayed, it will be null
    if(cell) {
    var ctlHost = cell.querySelector('.wj-control');
    var ctl = wijmo.Control.getControl(ctlHost);
    if(ctl) {
    ctl.lostFocus.addHandler(...);
    }
    }
    }

    Let us know if this works for you or otherwise.

    Regarding the datamap, setting the DataMap of the column will always refresh the grid and therefore the updateCell method will be called again. Also, the DataMap works on column level and with the same itemsSource but in your case, each row has a different itemsSource so we would not suggest you use DataMaps for your requirements.

    We hope this helps.

    Regards,
    Ashwin
Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels