Disable a PivotPanel Checkbox Field in React

Background:
Sometimes, you may want to disable the checkbox of a specific field in your PivotPanel to prevent users from interacting with it.
Steps to Complete:
- Create the PivotEngine
- Track which fields to disable
- Render the PivotPanel
- Disable checkboxes via the fields grid’s
formatItem
Getting Started:
Create the PivotEngine
Build the engine the Panel/Grid will share.
// src/olap/data.ts
export type OrderRow = {
Country: string; Category: string; Product: string;
Amount: number; Quantity: number; Date: Date;
};
export function makeData(rows = 200): OrderRow[] {
const countries = ['US', 'UK', 'Germany', 'Japan'];
const cats = ['Electronics', 'Clothing'];
const prods: Record<string, string[]> = {
Electronics: ['Phone', 'Laptop', 'Tablet'],
Clothing: ['Shirt', 'Jacket', 'Jeans'],
};
const out: OrderRow[] = [];
for (let i = 0; i < rows; i++) {
const c = countries[(Math.random() * countries.length) | 0];
const cat = cats[(Math.random() * cats.length) | 0];
const p = prods[cat][(Math.random() * prods[cat].length) | 0];
out.push({
Country: c, Category: cat, Product: p,
Amount: +(Math.random() * 1000).toFixed(2),
Quantity: 1 + (Math.random() * 10) | 0,
Date: new Date(2024, (Math.random() * 12) | 0, 1 + (Math.random() * 28) | 0),
});
}
return out;
}
// src/olap/engine.ts
import * as wjOlap from '@mescius/wijmo.olap';
import { makeData } from './data';
export function createEngine(): wjOlap.PivotEngine {
return new wjOlap.PivotEngine({
itemsSource: makeData(),
fields: [
{ binding: 'Country', header: 'Country' },
{ binding: 'Category', header: 'Category' },
{ binding: 'Product', header: 'Product' },
{ binding: 'Amount', header: 'Amount', format: 'n2' },
{ binding: 'Quantity', header: 'Quantity' },
{ binding: 'Date', header: 'Date' },
],
rowFields: ['Country'],
valueFields: ['Amount', 'Quantity'],
});
}
Track which fields to disable
Central list of protected field headers.
// inside your React component file
const [disabledFields] = React.useState<string[]>(['Amount']); // edit as needed
Render the PivotPanel and PivotGrid
Create refs and bind the shared engine.
// src/App.tsx
import React from 'react';
import * as wjOlap from '@mescius/wijmo.olap';
import { PivotPanel, PivotGrid } from '@mescius/wijmo.react.olap';
import { createEngine } from './olap/engine';
export default function App() {
const panelRef = React.useRef<any>(null);
const engine = React.useMemo<wjOlap.PivotEngine>(() => createEngine(), []);
const [disabledFields] = React.useState<string[]>(['Amount']);
// next steps will add effects here…
return (
<div style={{ fontFamily: 'system-ui, Segoe UI, Arial', padding: 16 }}>
<h2>Wijmo PivotPanel (React) — Disable specific field checkboxes</h2>
<PivotPanel ref={panelRef} itemsSource={engine} />
<PivotGrid itemsSource={engine} />
<p>Disabled fields: <code>{disabledFields.join(', ')}</code></p>
</div>
);
}
Disable checkboxes via the fields grid’s formatItem
Hook the internal fields list grid (_lbFields) formatItem and disable the <input type="checkbox"> when the field header matches.
// add inside App() after refs/state
React.useEffect(() => {
const panel = panelRef.current?.control as wjOlap.PivotPanel | undefined;
const fieldsGrid = (panel as any)?._lbFields; // private; may change across versions
if (!fieldsGrid?.formatItem) return;
const handler = (s: any, e: any) => {
if (e.panel === s.cells) {
const row = e.getRow();
const col = e.getColumn();
const header = row?.dataItem?.[col?.binding];
if (disabledFields.includes(header)) {
const chk: HTMLInputElement | null = e.cell.querySelector('input[type="checkbox"]');
if (chk) chk.disabled = true; // why: prevent toggling protected fields
}
}
};
fieldsGrid.formatItem.addHandler(handler);
return () => fieldsGrid.formatItem.removeHandler(handler);
}, [disabledFields]);
If implemented correctly, your checkboxes should now be disabled/protected. I hope you find this article helpful. Happy coding!
Full code file to reference:
// src/App.tsx
import React from 'react';
import * as wjOlap from '@mescius/wijmo.olap';
import { PivotPanel, PivotGrid } from '@mescius/wijmo.react.olap';
// -------- data helpers ----------
type OrderRow = {
Country: string; Category: string; Product: string;
Amount: number; Quantity: number; Date: Date;
};
function makeData(rows = 200): OrderRow[] {
const countries = ['US', 'UK', 'Germany', 'Japan'];
const cats = ['Electronics', 'Clothing'];
const prods: Record<string, string[]> = {
Electronics: ['Phone', 'Laptop', 'Tablet'],
Clothing: ['Shirt', 'Jacket', 'Jeans'],
};
const out: OrderRow[] = [];
for (let i = 0; i < rows; i++) {
const c = countries[(Math.random() * countries.length) | 0];
const cat = cats[(Math.random() * cats.length) | 0];
const p = prods[cat][(Math.random() * prods[cat].length) | 0];
out.push({
Country: c, Category: cat, Product: p,
Amount: +(Math.random() * 1000).toFixed(2),
Quantity: 1 + (Math.random() * 10) | 0,
Date: new Date(2024, (Math.random() * 12) | 0, 1 + (Math.random() * 28) | 0),
});
}
return out;
}
function createEngine(): wjOlap.PivotEngine {
return new wjOlap.PivotEngine({
itemsSource: makeData(),
fields: [
{ binding: 'Country', header: 'Country' },
{ binding: 'Category', header: 'Category' },
{ binding: 'Product', header: 'Product' },
{ binding: 'Amount', header: 'Amount', format: 'n2' },
{ binding: 'Quantity', header: 'Quantity' },
{ binding: 'Date', header: 'Date' },
],
rowFields: ['Country'],
valueFields: ['Amount', 'Quantity'],
});
}
export default function App() {
const panelRef = React.useRef<any>(null);
const engine = React.useMemo<wjOlap.PivotEngine>(() => createEngine(), []);
// fields to protect
const [disabledFields] = React.useState<string[]>(['Amount']);
// disable checkboxes in the fields list
React.useEffect(() => {
const panel = panelRef.current?.control as wjOlap.PivotPanel | undefined;
const fieldsGrid = (panel as any)?._lbFields;
if (!fieldsGrid?.formatItem) return;
const handler = (s: any, e: any) => {
if (e.panel === s.cells) {
const row = e.getRow();
const col = e.getColumn();
const header = row?.dataItem?.[col?.binding];
if (disabledFields.includes(header)) {
const chk: HTMLInputElement | null = e.cell.querySelector('input[type="checkbox"]');
if (chk) chk.disabled = true; // why: make protected fields non-toggleable
}
}
};
fieldsGrid.formatItem.addHandler(handler);
return () => fieldsGrid.formatItem.removeHandler(handler);
}, [disabledFields]);
// optional: block "Remove Field" in context menu
React.useEffect(() => {
const panel = panelRef.current?.control as wjOlap.PivotPanel | undefined;
if (!panel) return;
try {
const MenuProto = (wjOlap as any)._ListContextMenu?.prototype;
if (MenuProto && !MenuProto.__patched && MenuProto._canExecute) {
const original = MenuProto._canExecute;
MenuProto._canExecute = function (this: any, cmd: string) {
const isRemove = /remove(field)?/i.test(cmd ?? '');
const header = this?._targetField?.header;
const owner = (this?.ownerPivotPanel ?? this?.hostPivotPanel)?.owner;
if (isRemove && header && owner?.disabledFields?.includes(header)) return false;
return original.apply(this, arguments as any);
};
MenuProto.__patched = true;
(panel as any).owner = { disabledFields }; // surface to menu
}
} catch { /* ignore if internals differ */ }
}, [disabledFields]);
return (
<div style={{ fontFamily: 'system-ui, Segoe UI, Arial', padding: 16 }}>
<h2>Wijmo PivotPanel (React) — Disable specific field checkboxes</h2>
<PivotPanel ref={panelRef} itemsSource={engine} />
<PivotGrid itemsSource={engine} />
<p>Disabled fields: <code>{disabledFields.join(', ')}</code></p>
</div>
);
}