FrozenCells API

The Cell Freeze feature in FlexGrid allows users to lock certain rows and columns, ensuring they remain visible while scrolling through other parts of the grid. Previously, FlexGrid supported freezing cells on the left and top using FrozenRows and FrozenColumns. The feature has now been enhanced with the FrozenCells to include options for freezing cells on the right and bottom as well.

Supported Operations

  1. Freeze columns on the left or right
  2. Freeze rows at the top or bottom
  3. Combine one horizontal (left or right) and one vertical (top or bottom) freeze

Important: While the frozenCells API provides options for all four sides, you can only freeze cells on two sides simultaneously:

  • One horizontal side (either left OR right)
  • One vertical side (either top OR bottom)

Note:

  • If both left and right are set, left will take effect.
  • Similarly, if both top and bottom, top will be applied.

Learn about FlexGrid | FlexGrid API Reference

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; import { FlexGrid } from '@mescius/wijmo.grid'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { // generate some random data var countries = 'US,Germany,UK,Japan,Italy,Greece'.split(','), data = []; for (var i = 0; i < 200; i++) { data.push({ id: i, country: countries[i % countries.length], downloads: Math.round(Math.random() * 20000), sales: Math.random() * 10000, expenses: Math.random() * 5000, num1: Math.random() * 5000, num2: Math.random() * 5000, num3: Math.random() * 5000, num4: Math.random() * 5000, num5: Math.random() * 5000, }); } // default behavior: allow column reordering let theGrid = new FlexGrid('#theGrid', { itemsSource: data, allowPinning: 'Both', }); // Add event listener for the new freeze cells button document.querySelector('#btnFreezeCells').addEventListener('click', freezeCells); function freezeCells() { const frozenCells = { top: parseInt(document.getElementById('topFreeze').value) || 0, bottom: parseInt(document.getElementById('bottomFreeze').value) || 0, left: parseInt(document.getElementById('leftFreeze').value) || 0, right: parseInt(document.getElementById('rightFreeze').value) || 0 }; // Apply the frozenCells to the grid theGrid.frozenCells = frozenCells; // Read back what was actually applied const appliedFrozenCells = theGrid.frozenCells; // Prepare the message const messageElement = document.getElementById('errorMsg'); let appliedFreezeMsg = "Applied freeze: "; if (Object.keys(appliedFrozenCells).length === 0) { appliedFreezeMsg += "None"; } else { appliedFreezeMsg += Object.entries(appliedFrozenCells) .map(([key, value]) => `${key}: ${value}`) .join(', '); } // Display the message messageElement.style.display = 'block'; messageElement.style.color = 'green'; messageElement.textContent = appliedFreezeMsg; } // Add event listeners for disabling inputs const inputs = { top: document.getElementById('topFreeze'), bottom: document.getElementById('bottomFreeze'), left: document.getElementById('leftFreeze'), right: document.getElementById('rightFreeze') }; // Add event listener for the clear freeze cells button document.querySelector('#btnClearFreezeCells').addEventListener('click', clearFreezeCells); function clearFreezeCells() { theGrid.frozenCells = { top: 0, bottom: 0, left: 0, right: 0 }; Object.values(inputs).forEach(input => input.value = '0'); handleInputChange(); document.getElementById('errorMsg').innerHTML = ""; } const handleInputChange = () => { const topValue = parseInt(inputs.top.value, 10) || 0; const bottomValue = parseInt(inputs.bottom.value, 10) || 0; const leftValue = parseInt(inputs.left.value, 10) || 0; const rightValue = parseInt(inputs.right.value, 10) || 0; toggleDisable(topValue, inputs.bottom); toggleDisable(bottomValue, inputs.top); toggleDisable(leftValue, inputs.right); toggleDisable(rightValue, inputs.left); }; // Attach input event listeners Object.values(inputs).forEach(input => { input.addEventListener('input', handleInputChange); }); const toggleDisable = (primaryValue, secondaryElement) => { secondaryElement.disabled = primaryValue > 0; }; }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo FlexGrid Frozen Rows and Columns</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.21.5/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div class="container-fluid"> <div class="flex-grow-0"> <div id="freezeControls"> <h2 class="text-center">Grid Freeze Cells API</h2> <div class="inputs"> <div class="inputRow"> <div class="ctrl"> <label for="topFreeze" class="form-label">Freeze Rows (Top):</label> <input type="number" id="topFreeze" min="0" value="0" class="form-control" /> </div> <div class="ctrl"> <label for="bottomFreeze" class="form-label">Freeze Rows (Bottom):</label> <input type="number" id="bottomFreeze" min="0" value="0" class="form-control" /> </div> </div> <div class="inputRow"> <div class="ctrl"> <label for="leftFreeze" class="form-label">Freeze Columns (Left):</label> <input type="number" id="leftFreeze" min="0" value="0" class="form-control" /> </div> <div class="ctrl"> <label for="rightFreeze" class="form-label">Freeze Columns (Right):</label> <input type="number" id="rightFreeze" min="0" value="0" class="form-control" /> </div> </div> </div> <div class="d-grid gap-2 freezeBtns"> <button type="button" class="btn btn-primary" id="btnFreezeCells">Apply Freeze</button> <button type="button" class="btn btn-primary" id="btnClearFreezeCells">Clear Freeze</button> </div> <p id="errorMsg" class="text-center"></p> </div> </div> <div class="flex-grow-1 flex-container"> <div id="theGrid"></div> </div> </div> </body> </html>
.wj-flexgrid { max-height: 400px; max-width: 1000px; margin: 10px 0; } /* style frozen cells */ .wj-cell.wj-frozen:not(.wj-header):not(.wj-group):not(.wj-state-selected):not(.wj-state-multi-selected), .wj-cell.wj-frozen.wj-alt:not(.wj-header):not(.wj-group):not(.wj-state-selected):not(.wj-state-multi-selected) { background: rgb(255, 255, 125); } html, body { height: 800px; margin: 0; padding: 0; overflow: hidden; } .container-fluid { height: 100vh; display: flex; flex-direction: column; padding: 15px; box-sizing: border-box; overflow: hidden; margin: 0px 10px } #freezeControls { max-width:1000px; background-color: #f8f9fa; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); padding: 20px; margin-bottom: 15px; } #freezeControls h2 { color: #007bff; margin-bottom: 20px; } .control-group { margin-bottom: 15px; } #errorMsg { color: #dc3545; font-weight: bold; margin-top: 10px; } .grid-container { flex-grow: 1; min-height: 0; /* Important for Firefox */ display: flex; flex-direction: column; } .inputRow{ display: flex; justify-content: space-between; } .ctrl{ width: 100%; margin: 0px 10px; } .freezeBtns button{ margin: 10px } .flex-container { display: flex; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'jszip': 'npm:jszip/dist/jszip.js', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js', '@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js', '@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js', '@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js', '@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js', '@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js', '@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js', '@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js', '@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js', '@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js', '@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js', '@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js', '@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js', '@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js', '@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js', '@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js', '@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js', '@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js', '@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js', '@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js', '@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js', '@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js', '@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js', '@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js', '@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js', '@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js', '@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js', '@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js', '@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js', '@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js', '@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js', '@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js', '@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js', '@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js', '@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js', '@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js', '@mescius/wijmo.barcode.specialized': 'npm:@mescius/wijmo.barcode.specialized/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);