typescript - Rendera Angular-komponenter i Handsontable-celler
I ett av mina projekt försöker jag visa Angular-komponenter (som en autokompletterande rullgardinsökning) i en tabell. På grund av de krav jag har (som att kunna markera flera olika celler med ctrl+klick) bestämde jag mig för att prova med handsontable.
Jag har använt handsontable-renderaren och lagt till komponenterna dynamiskt.
Koden ser ut så här
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;
}
Mitt nuvarande problem är livscykeln för de renderade Angular-komponenterna.
Saker jag försökte:
- Gör ingenting
Försökt lösning: Att göra ingenting och lämna allt till Angular
Problem: Angular anropar aldrig ngOnDestroy för CellContainer.
- Sparar componentRefs
Försökt lösning: Spara componentRef i en array och efter ett visst antal renderingar försöka förstöra de komponenter jag renderade för ett tag sedan. Räkna via tid, handsontable-hooks (verticalScroll/beforeRender/afterRender), i render-metoden
Problem: Att förstöra Angular-komponenten ger alltid ett fel ('kan inte läsa egenskapen 'nativeNode' av null') eller så visas komponenterna helt fel
- Kontrollera under rendering om ett element finns där
Försökt lösning: Under renderingen: Jag kontrollerade om det redan finns en komponent och om det gjorde det använde jag att återanvända den redan existerande komponenten genom att bara lägga till ett nytt värde.
Problem: Värdena blir helt blandade vid bläddring.
En länk till min lösning (och en implementerad lösning #3) finns på GitHub.
Har någon en idé om hur man hanterar detta på ett smidigt sätt? Om inte blir applikationen långsam och oanvändbar efter lite rullning och användning av tabellen. Bättre referens: https://handsontable.com/docs/8.2.0/tutorial-cell-function.html
Svar #1
Använder en cell-renderare. Använd det renderarens namn du vill när du konfigurerar kolumnen:
const container = document.getElementById('container');
const hot = new Handsontable(container,
{
data: someData,
columns:
[{
renderer: 'numeric'
}]
});
Svar #2
kanske behöver du prova changeDetection som nedan, vilket tvingar fram de nya förändringarna i din komponent.
changeDetection: ChangeDetectionStrategy.OnPush
