@asif-dev/ng-pivottable
Version:
Angular wrappers for react-pivottable (PivotTable and PivotTableUI) — React 17
294 lines (288 loc) • 13.6 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, NgZone, PLATFORM_ID, Component, ChangeDetectionStrategy, Input, ViewChild, EventEmitter, ChangeDetectorRef, Output } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import PivotTable from 'react-pivottable/PivotTable';
import PivotTableUI from 'react-pivottable/PivotTableUI';
// projects/angular-pivottable/src/lib/pivot-table/pivot-table.component.ts
class NgPivotTableComponent {
constructor() {
this.data = [];
this.rows = [];
this.cols = [];
this.vals = [];
this.aggregatorName = 'Count';
this.ngZone = inject(NgZone);
this.platformId = inject(PLATFORM_ID);
this.isInitialized = false;
this.isBrowser = isPlatformBrowser(this.platformId);
}
ngAfterViewInit() {
if (this.isBrowser && this.containerRef?.nativeElement) {
this.isInitialized = true;
this.renderReact();
}
}
ngOnChanges(changes) {
// Only re-render if component is initialized and we're in browser
if (this.isInitialized && this.isBrowser) {
this.renderReact();
}
}
renderReact() {
if (!this.containerRef?.nativeElement) {
return;
}
// Run React rendering outside Angular's zone to prevent unnecessary change detection
this.ngZone.runOutsideAngular(() => {
try {
const props = {
data: this.data || [],
rows: this.rows || [],
cols: this.cols || [],
vals: this.vals || [],
aggregatorName: this.aggregatorName || 'Count',
rendererName: this.rendererName,
valueFilter: this.valueFilter,
sorters: this.sorters,
derivedAttributes: this.derivedAttributes,
hiddenAttributes: this.hiddenAttributes,
hiddenFromAggregators: this.hiddenFromAggregators,
hiddenFromDragDrop: this.hiddenFromDragDrop,
menuLimit: this.menuLimit,
unusedOrientationCutoff: this.unusedOrientationCutoff
};
// Remove undefined properties
Object.keys(props).forEach(key => {
if (props[key] === undefined) {
delete props[key];
}
});
ReactDOM.render(React.createElement(PivotTable, props), this.containerRef.nativeElement);
}
catch (error) {
console.error('Error rendering PivotTable:', error);
}
});
}
ngOnDestroy() {
if (this.isBrowser && this.containerRef?.nativeElement) {
try {
ReactDOM.unmountComponentAtNode(this.containerRef.nativeElement);
}
catch (error) {
console.error('Error unmounting PivotTable:', error);
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgPivotTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: NgPivotTableComponent, isStandalone: true, selector: "ng-pivot-table", inputs: { data: "data", rows: "rows", cols: "cols", vals: "vals", aggregatorName: "aggregatorName", rendererName: "rendererName", valueFilter: "valueFilter", sorters: "sorters", derivedAttributes: "derivedAttributes", hiddenAttributes: "hiddenAttributes", hiddenFromAggregators: "hiddenFromAggregators", hiddenFromDragDrop: "hiddenFromDragDrop", menuLimit: "menuLimit", unusedOrientationCutoff: "unusedOrientationCutoff" }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `<div #container class="ng-pivottable-root"></div>`, isInline: true, styles: [":host{display:block}.ng-pivottable-root{width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgPivotTableComponent, decorators: [{
type: Component,
args: [{ selector: 'ng-pivot-table', template: `<div #container class="ng-pivottable-root"></div>`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, styles: [":host{display:block}.ng-pivottable-root{width:100%}\n"] }]
}], ctorParameters: () => [], propDecorators: { data: [{
type: Input
}], rows: [{
type: Input
}], cols: [{
type: Input
}], vals: [{
type: Input
}], aggregatorName: [{
type: Input
}], rendererName: [{
type: Input
}], valueFilter: [{
type: Input
}], sorters: [{
type: Input
}], derivedAttributes: [{
type: Input
}], hiddenAttributes: [{
type: Input
}], hiddenFromAggregators: [{
type: Input
}], hiddenFromDragDrop: [{
type: Input
}], menuLimit: [{
type: Input
}], unusedOrientationCutoff: [{
type: Input
}], containerRef: [{
type: ViewChild,
args: ['container', { static: true }]
}] } });
// projects/angular-pivottable/src/lib/pivot-table-ui/pivot-table-ui.component.ts
class NgPivotTableUiComponent {
constructor() {
this.data = [];
this.rows = [];
this.cols = [];
this.vals = [];
this.aggregatorName = 'Count';
this.configChange = new EventEmitter();
this.stateChange = new EventEmitter();
this.ngZone = inject(NgZone);
this.cdr = inject(ChangeDetectorRef);
this.platformId = inject(PLATFORM_ID);
this.isInitialized = false;
this.internalState = {};
this.shouldUpdateFromInputs = true;
this.isBrowser = isPlatformBrowser(this.platformId);
}
ngAfterViewInit() {
if (this.isBrowser && this.containerRef?.nativeElement) {
this.isInitialized = true;
this.initializeInternalState();
this.renderReact();
}
}
ngOnChanges(changes) {
if (this.isInitialized && this.isBrowser && this.shouldUpdateFromInputs) {
// Only update internal state from inputs if we're not in the middle of a React onChange
const hasRelevantChanges = Object.keys(changes).some(key => key !== 'data' || changes[key].currentValue !== changes[key].previousValue);
if (hasRelevantChanges) {
this.initializeInternalState();
this.renderReact();
}
}
}
initializeInternalState() {
// Initialize internal state from inputs
this.internalState = {
data: this.data || [],
rows: this.rows || [],
cols: this.cols || [],
vals: this.vals || [],
aggregatorName: this.aggregatorName || 'Count',
rendererName: this.rendererName,
valueFilter: this.valueFilter,
sorters: this.sorters,
derivedAttributes: this.derivedAttributes,
hiddenAttributes: this.hiddenAttributes,
hiddenFromAggregators: this.hiddenFromAggregators,
hiddenFromDragDrop: this.hiddenFromDragDrop,
menuLimit: this.menuLimit,
unusedOrientationCutoff: this.unusedOrientationCutoff
};
// Remove undefined properties
Object.keys(this.internalState).forEach(key => {
if (this.internalState[key] === undefined) {
delete this.internalState[key];
}
});
}
renderReact() {
if (!this.containerRef?.nativeElement) {
return;
}
// Run React rendering outside Angular's zone
this.ngZone.runOutsideAngular(() => {
try {
const props = {
...this.internalState,
onChange: (newState) => {
// Prevent input changes from overriding React's state during onChange
this.shouldUpdateFromInputs = false;
// Update internal state
this.internalState = { ...newState };
// Run emissions inside Angular zone to trigger change detection if needed
this.ngZone.run(() => {
this.configChange.emit({ ...newState });
this.stateChange.emit({ ...newState });
// Mark for check in case parent component needs to update
this.cdr.markForCheck();
});
// Re-render with new state
this.renderReact();
// Re-enable input updates after a microtask
Promise.resolve().then(() => {
this.shouldUpdateFromInputs = true;
});
}
};
ReactDOM.render(React.createElement(PivotTableUI, props), this.containerRef.nativeElement);
}
catch (error) {
console.error('Error rendering PivotTableUI:', error);
}
});
}
/**
* Programmatically update the pivot table state
* @param state - Partial state to merge with current state
*/
updateState(state) {
this.internalState = { ...this.internalState, ...state };
if (this.isInitialized) {
this.renderReact();
}
}
/**
* Get the current pivot table state
*/
getState() {
return { ...this.internalState };
}
ngOnDestroy() {
if (this.isBrowser && this.containerRef?.nativeElement) {
try {
ReactDOM.unmountComponentAtNode(this.containerRef.nativeElement);
}
catch (error) {
console.error('Error unmounting PivotTableUI:', error);
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgPivotTableUiComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: NgPivotTableUiComponent, isStandalone: true, selector: "ng-pivot-table-ui", inputs: { data: "data", rows: "rows", cols: "cols", vals: "vals", aggregatorName: "aggregatorName", rendererName: "rendererName", valueFilter: "valueFilter", sorters: "sorters", derivedAttributes: "derivedAttributes", hiddenAttributes: "hiddenAttributes", hiddenFromAggregators: "hiddenFromAggregators", hiddenFromDragDrop: "hiddenFromDragDrop", menuLimit: "menuLimit", unusedOrientationCutoff: "unusedOrientationCutoff" }, outputs: { configChange: "configChange", stateChange: "stateChange" }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `<div #container class="ng-pivottable-ui-root"></div>`, isInline: true, styles: [":host{display:block}.ng-pivottable-ui-root{width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgPivotTableUiComponent, decorators: [{
type: Component,
args: [{ selector: 'ng-pivot-table-ui', template: `<div #container class="ng-pivottable-ui-root"></div>`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, styles: [":host{display:block}.ng-pivottable-ui-root{width:100%}\n"] }]
}], ctorParameters: () => [], propDecorators: { data: [{
type: Input
}], rows: [{
type: Input
}], cols: [{
type: Input
}], vals: [{
type: Input
}], aggregatorName: [{
type: Input
}], rendererName: [{
type: Input
}], valueFilter: [{
type: Input
}], sorters: [{
type: Input
}], derivedAttributes: [{
type: Input
}], hiddenAttributes: [{
type: Input
}], hiddenFromAggregators: [{
type: Input
}], hiddenFromDragDrop: [{
type: Input
}], menuLimit: [{
type: Input
}], unusedOrientationCutoff: [{
type: Input
}], configChange: [{
type: Output
}], stateChange: [{
type: Output
}], containerRef: [{
type: ViewChild,
args: ['container', { static: true }]
}] } });
/*
* Public API Surface of angular-pivottable
*/
/**
* Generated bundle index. Do not edit.
*/
export { NgPivotTableComponent, NgPivotTableUiComponent };
//# sourceMappingURL=angular-pivottable.mjs.map