Rendering Angular components in Handsontable Cells
Asked Answered
S

2

241

In a project of mine, I try to display Angular Components (like an Autocomplete Dropdown Search) in a table. Because of the requirements I have (like multi-selecting different cells with ctrl+click) I decided to give it a go with handsontable.

I've used the handsontable renderer and add the components dynamically.

The code looks like this

matrix.component.ts

this.hot = new Handsontable(this.handsontable.nativeElement, {
  data: this.tableData,
  colWidths: [80, 300],
  colHeaders: ['Id', 'Custom Component'],
  columns: [
    {
      data: 'id',
    },
    {
      data: 'id',
      renderer: (instance: any, td: any, row: any, col: any, prop: any, value: any, cellProperties: any) => {
        if (cellProperties.hasOwnProperty('ref')) {
          (cellProperties.ref as ComponentRef<CellContainerComponent>).instance.value = row;
        } else {
          cellProperties.ref = this.loadComponentAtDom(
            CellContainerComponent,
            td,
            ((component: any) => {
              component.template = this.button4Matrix;
              component.value = row;
            }));
        }
        return td;
      },
      readOnly: true,
    },
  ],
});


private loadComponentAtDom<T>(component: Type<T>, dom: Element, onInit?: (component: T) => void): ComponentRef<T> {
  let componentRef;
  try {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
    componentRef = componentFactory.create(this.injector, [], dom);
    onInit ? onInit(componentRef.instance) : console.log('no init');
    this.appRef.attachView(componentRef.hostView);
  } catch (e) {
    console.error('Unable to load component', component, 'at', dom);
    throw e;
  }
  return componentRef;
}

What's my current issue is the lifecycle of the rendered angular components.

Stuff I tried:

  1. Do nothing

Tried Solution: Doing nothing and leaving everything to Angular

Problem: Angular never calling the ngOnDestroy of the CellContainer.

  1. Saving componentRefs

Tried Solution: Saving the componentRef in an Array and after a certain amount of rendering trying to destroy the components I rendered some time ago. Counting via time, handsontable hooks (verticalScroll/beforeRender/afterRender), in the render-method

Problem: Destroy of the angular component always throws an error ('cannot read property'nativeNode' of null') or the components get displayed completely wrong

  1. Check during rendering if an element is there

Tried Solution: During the render: I checked if there's already a component and if it was I used to recycle the already-there component by adding a new value only.

Problem: The values get completely mixed up during scrolling.

A link to my solution (and an implemented solution #3) is available on github.

Does anyone have an idea of how to handle this in a clean way? If not the application gets slow & unusable after a little bit of scrolling & using the table. Better refer : https://handsontable.com/docs/8.2.0/tutorial-cell-function.html

Sportsmanship answered 15/3, 2018 at 9:42 Comment(5)
I decided to go with ag-grid community edition instead of handsontable. The lifecycle of rendered cells is very easy to take care of there.. I also checked out ngx-datatable, but it does currently not support fixed columns which is one of the requirements of the project..Sportsmanship
Is this answer helpful? https://mcmap.net/q/119304/-dynamically-adding-and-removing-components-in-angularAugusto
There was a CSS issue occured when I try to integrate and this was fixed by this import in my common CSSThickening
Can you fix the link to the repo?Molar
hmm there exist angular integration for handsontable npmjs.com/package/@handsontable/angular did you try using it?Jarry
W
1

Using a cell renderer. Use the renderer name of your choice when configuring the column:

const container = document.getElementById('container');

const hot = new Handsontable(container,
 {
  data: someData,
  columns: 
[{
    renderer: 'numeric'
  }]

});
Westphalia answered 3/8, 2021 at 11:9 Comment(0)
P
-5

may be you need to try changeDetection as below, forcing the new changes to your component.

changeDetection: ChangeDetectionStrategy.OnPush
Poddy answered 17/6, 2021 at 8:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.