Row and Column Freezing (Vue)

The MultiRow control allows you to freeze rows and columns so they remain in view as the user scrolls the grid. You can set the number of frozen rows and columns through the frozenColumns and frozenRows properties.

Frozen cells can be edited and selected as regular cells, exactly as in Excel and in the FlexGrid control.

This example allows you to toggle whether the first group of rows and columns should be frozen.

Learn about MultiRow | MultiRow API Reference

This example uses Vue.

<template> <div class="container-fluid"> <wj-multi-row :initialized="initSlip" :itemsSource="orders" :layoutDefinition="layoutDefinition"></wj-multi-row> <br /> <button class="btn btn-default" @click="onFreezeClick" v-html="textContent"> </button> </div> </template> <script> import '@mescius/wijmo.styles/wijmo.css'; import { createApp } from "vue" import { registerCore } from '@mescius/wijmo.vue2.core'; import { registerGridMultirow } from '@mescius/wijmo.vue2.grid.multirow'; import { generateAppData } from './data'; let App = { name: 'app', data: function () { let data = generateAppData(); return { orders: data.orders, layoutDefinition: data.ldTwoLines, textContent: 'Freeze', freezeMultirow: null } }, methods: { initSlip: function (freezeMultirow) { this.freezeMultirow = freezeMultirow; }, onFreezeClick: function () { this.freezeMultirow.frozenColumns = this.freezeMultirow.frozenColumns ? 0 : 2; this.freezeMultirow.frozenRows = this.freezeMultirow.frozenRows ? 0 : 2; this.textContent = this.freezeMultirow.frozenRows == 0 ? 'Freeze' : 'Unfreeze'; } } }; const app = createApp(App); // register all components and directives from Wijmo modules registerCore(app) registerGridMultirow(app) app.mount('#app'); </script> <style> @import "./node_modules/bootstrap/dist/css/bootstrap.css"; .wj-control.wj-multirow { height: 400px; width: 600px; margin: 6px 0; } /* custom styling for frozen cells */ .wj-flexgrid .wj-cell.wj-frozen:not(.wj-header):not(.wj-group):not(.wj-state-selected):not(.wj-state-multi-selected) { background-color: #f3fbcc; } </style>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo MultiRow Row and Column Freezing</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.vue'); </script> </head> <body> <div id="app"> </div> </body> </html>
import * as wjCore from '@mescius/wijmo'; import * as wjGrid from '@mescius/wijmo.grid'; export function generateAppData(){ // create some data let appData = {}, customers = [], firstNames = 'Aaron,Paul,John,Mark,Sue,Tom,Bill,Joe,Tony,Brad,Frank,Chris,Pat'.split(','), lastNames = 'Smith,Johnson,Richards,Bannon,Wong,Peters,White,Brown,Adams,Jennings'.split(','), cities = 'York,Paris,Rome,Cairo,Florence,Sidney,Hamburg,Vancouver'.split(','), states = 'SP,RS,RN,SC,CS,RT,BC'.split(','); for (let i = 0; i < 50; i++) { let first = firstNames[randBetween(0, firstNames.length - 1)], last = lastNames[randBetween(0, lastNames.length - 1)]; customers.push({ id: i, name: first + ' ' + last, address: randBetween(100, 10000) + ' ' + lastNames[randBetween(0, lastNames.length - 1)] + ' St.', city: cities[randBetween(0, cities.length - 1)], state: states[randBetween(0, states.length - 1)], zip: wjCore.format('{p1:d5}-{p2:d3}', { p1: randBetween(10000, 99999), p2: randBetween(100, 999) }), email: first + '.' + last + '@gmail.com', phone: wjCore.format('{p1:d3}-{p2:d4}', { p1: randBetween(100, 999), p2: randBetween(1000, 9999) }) }); } let cityMap = new wjGrid.DataMap(cities); let shippers = [ { id: 0, name: 'Speedy Express', email: 'speedy@gmail.com', phone: '431-3234', express: true }, { id: 1, name: 'Flash Delivery', email: 'flash@gmail.com', phone: '431-6563', express: true }, { id: 2, name: 'Logitrax', email: 'logitrax@gmail.com', phone: '431-3981', express: false }, { id: 3, name: 'Acme Inc', email: 'acme@gmail.com', phone: '431-3113', express: false } ]; let orders = []; let today = new Date(); for (let i = 0; i < 20; i++) { let shipped = wjCore.DateTime.addDays(today, -randBetween(1, 3000)); orders.push({ id: i, date: wjCore.DateTime.addDays(shipped, -randBetween(1, 5)), shippedDate: shipped, amount: randBetween(10000, 500000) / 100, customer: customers[randBetween(0, customers.length - 1)], shipper: shippers[randBetween(0, shippers.length - 1)] }); } function randBetween(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } // expose orders CollectionView to the app appData.orders = new wjCore.CollectionView(orders); // expose grouped orders CollectionView to the app appData.groupedOrders = new wjCore.CollectionView(orders, { groupDescriptions: [ 'customer.city' ] }); // expose paged orders CollectionView to the app appData.pagedOrders = new wjCore.CollectionView(orders, { pageSize: 4 }); // expose addNew oders CollectionView to the app appData.addNewOrders = new wjCore.CollectionView(orders, { newItemCreator: function () { return { // add empty customer and shipper objects to new orders customer: {}, shipper: {} } }, }); appData.addNewOrders.moveCurrentToLast(); // refresh views when data source changes let ordersRefreshing = false; appData.orders.collectionChanged.addHandler(function () { ordersRefreshing = true; if (!pagedOrdersRefreshing) { appData.pagedOrders.refresh(); } if (!groupedOrdersRefreshing) { appData.groupedOrders.refresh(); } if (!addNewOrdersRefreshing) { appData.addNewOrders.refresh(); } ordersRefreshing = false; }); // addNew orders let addNewOrdersRefreshing = false; appData.addNewOrders.collectionChanged.addHandler(function () { addNewOrdersRefreshing = true; if (!ordersRefreshing) { appData.orders.refresh(); } if (!pagedOrdersRefreshing) { appData.pagedOrders.refresh(); } if (!groupedOrdersRefreshing) { appData.groupedOrders.refresh(); } addNewOrdersRefreshing = false; }); // grouped orders let groupedOrdersRefreshing = false; appData.groupedOrders.collectionChanged.addHandler(function () { groupedOrdersRefreshing = true; if (!ordersRefreshing) { appData.orders.refresh(); } if (!pagedOrdersRefreshing) { appData.pagedOrders.refresh(); } if (!addNewOrdersRefreshing) { appData.addNewOrders.refresh(); } groupedOrdersRefreshing = false; }); // paged orders let pagedOrdersRefreshing = false; appData.pagedOrders.collectionChanged.addHandler(function () { pagedOrdersRefreshing = true; if (!ordersRefreshing) { appData.orders.refresh(); } if (!addNewOrdersRefreshing) { appData.addNewOrders.refresh(); } if (!groupedOrdersRefreshing) { appData.groupedOrders.refresh(); } pagedOrdersRefreshing = false; }); // sample layout definitions appData.ldOneLine = [ { cells: [{ binding: 'id', header: 'ID', cssClass: 'id', isReadOnly: true }] }, { cells: [{ binding: 'date', header: 'Ordered' }] }, { cells: [{ binding: 'shippedDate', header: 'Shipped' }] }, { cells: [{ binding: 'amount', header: 'Amount', format: 'c', cssClass: 'amount' }] }, { cells: [{ binding: 'customer.name', header: 'Customer' }] }, { cells: [{ binding: 'customer.address', header: 'Address', wordWrap: true }] }, { cells: [{ binding: 'customer.city', header: 'City', dataMap: cityMap }] }, { cells: [{ binding: 'customer.state', header: 'State', width: 45 }] }, { cells: [{ binding: 'customer.zip', header: 'Zip' }] }, { cells: [{ binding: 'customer.email', header: 'Customer Email', cssClass: 'email' }] }, { cells: [{ binding: 'customer.phone', header: 'Customer Phone' }] }, { cells: [{ binding: 'shipper.name', header: 'Shipper' }] }, { cells: [{ binding: 'shipper.email', header: 'Shipper Email', cssClass: 'email' }] }, { cells: [{ binding: 'shipper.phone', header: 'Shipper Phone' }] }, { cells: [{ binding: 'shipper.express', header: 'Express' }] } ]; appData.ldTwoLines = [ { header: 'Order', colspan: 2, cells: [ { binding: 'id', header: 'ID', cssClass: 'id', isReadOnly: true }, { binding: 'date', header: 'Ordered' }, { binding: 'amount', header: 'Amount', format: 'c', cssClass: 'amount' }, { binding: 'shippedDate', header: 'Shipped' } ] }, { header: 'Customer', colspan: 3, cells: [ { binding: 'customer.name', header: 'Name' }, { binding: 'customer.email', header: 'EMail', colspan: 2, cssClass: 'email' }, { binding: 'customer.address', header: 'Address' }, { binding: 'customer.city', header: 'City', dataMap: cityMap }, { binding: 'customer.state', header: 'State', width: 45 } ] }, { header: 'Shipper', cells: [ { binding: 'shipper.name', header: 'Shipper', colspan: 2 }, { binding: 'shipper.email', header: 'EMail', cssClass: 'email' }, { binding: 'shipper.express', header: 'Express' } ] } ]; appData.ldThreeLines = [ { header: 'Order', colspan: 2, cells: [ { binding: 'id', header: 'ID', colspan: 2, cssClass: 'id' }, { binding: 'amount', header: 'Amount', format: 'c', colspan: 2, cssClass: 'amount' }, { binding: 'date', header: 'Ordered' }, { binding: 'shippedDate', header: 'Shipped' } ] }, { header: 'Customer', colspan: 3, cells: [ { binding: 'customer.name', header: 'Name' }, { binding: 'customer.email', header: 'EMail', colspan: 2, cssClass: 'email' }, { binding: 'customer.address', header: 'Address', colspan: 2 }, { binding: 'customer.phone', header: 'Phone' }, { binding: 'customer.city', header: 'City', dataMap: cityMap }, { binding: 'customer.state', header: 'State', width: 45 }, { binding: 'customer.zip', header: 'Zip' }, ] }, { header: 'Shipper', cells: [ { binding: 'shipper.name', header: 'Shipper' }, { binding: 'shipper.email', header: 'EMail', cssClass: 'email' }, { binding: 'shipper.express', header: 'Express' } ] } ]; appData.layoutDefs = new wjCore.CollectionView([ { name: 'Traditional', description: 'Traditional grid view, with one row per record. The user must scroll horizontally to see the whole record.', def: appData.ldOneLine }, { name: 'Compact', description: 'This view uses two rows per record. The layout is divided into three groups: order, customer, and shipper', def: appData.ldTwoLines }, { name: 'Detailed', description: 'This view uses three rows per record. The layout is divided into three groups: order, customer, and shipper', def: appData.ldThreeLines } ]); return appData; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' }, '*.vue': { loader: 'vue-loader' } //'*.vue': { loader: 'systemjs-plugin-vue' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { '@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', "@mescius/wijmo.vue2.chart.analytics": "npm:@mescius/wijmo.vue2.chart.analytics/index.js", "@mescius/wijmo.vue2.chart.animation": "npm:@mescius/wijmo.vue2.chart.animation/index.js", "@mescius/wijmo.vue2.chart.annotation": "npm:@mescius/wijmo.vue2.chart.annotation/index.js", "@mescius/wijmo.vue2.chart.finance.analytics": "npm:@mescius/wijmo.vue2.chart.finance.analytics/index.js", "@mescius/wijmo.vue2.chart.finance": "npm:@mescius/wijmo.vue2.chart.finance/index.js", "@mescius/wijmo.vue2.chart.hierarchical": "npm:@mescius/wijmo.vue2.chart.hierarchical/index.js", "@mescius/wijmo.vue2.chart.interaction": "npm:@mescius/wijmo.vue2.chart.interaction/index.js", "@mescius/wijmo.vue2.chart.radar": "npm:@mescius/wijmo.vue2.chart.radar/index.js", '@mescius/wijmo.vue2.chart.map': 'npm:@mescius/wijmo.vue2.chart.map/index.js', "@mescius/wijmo.vue2.chart": "npm:@mescius/wijmo.vue2.chart/index.js", "@mescius/wijmo.vue2.core": "npm:@mescius/wijmo.vue2.core/index.js", "@mescius/wijmo.vue2.gauge": "npm:@mescius/wijmo.vue2.gauge/index.js", "@mescius/wijmo.vue2.grid.detail": "npm:@mescius/wijmo.vue2.grid.detail/index.js", "@mescius/wijmo.vue2.grid.filter": "npm:@mescius/wijmo.vue2.grid.filter/index.js", "@mescius/wijmo.vue2.grid.grouppanel": "npm:@mescius/wijmo.vue2.grid.grouppanel/index.js", '@mescius/wijmo.vue2.grid.search': 'npm:@mescius/wijmo.vue2.grid.search/index.js', "@mescius/wijmo.vue2.grid.multirow": "npm:@mescius/wijmo.vue2.grid.multirow/index.js", "@mescius/wijmo.vue2.grid.sheet": "npm:@mescius/wijmo.vue2.grid.sheet/index.js", '@mescius/wijmo.vue2.grid.transposed': 'npm:@mescius/wijmo.vue2.grid.transposed/index.js', '@mescius/wijmo.vue2.grid.transposedmultirow': 'npm:@mescius/wijmo.vue2.grid.transposedmultirow/index.js', "@mescius/wijmo.vue2.grid": "npm:@mescius/wijmo.vue2.grid/index.js", "@mescius/wijmo.vue2.input": "npm:@mescius/wijmo.vue2.input/index.js", "@mescius/wijmo.vue2.olap": "npm:@mescius/wijmo.vue2.olap/index.js", "@mescius/wijmo.vue2.viewer": "npm:@mescius/wijmo.vue2.viewer/index.js", "@mescius/wijmo.vue2.nav": "npm:@mescius/wijmo.vue2.nav/index.js", "@mescius/wijmo.vue2.base": "npm:@mescius/wijmo.vue2.base/index.js", '@mescius/wijmo.vue2.barcode.common': 'npm:@mescius/wijmo.vue2.barcode.common/index.js', '@mescius/wijmo.vue2.barcode.composite': 'npm:@mescius/wijmo.vue2.barcode.composite/index.js', '@mescius/wijmo.vue2.barcode.specialized': 'npm:@mescius/wijmo.vue2.barcode.specialized/index.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'jszip': 'npm:jszip/dist/jszip.js', 'css': 'npm:systemjs-plugin-css/css.js', 'vue': 'npm:vue/dist/vue.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', '@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js', '@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js', '@vue/shared':'npm:@vue/shared/dist/shared.cjs.js', 'vue-loader': 'npm:systemjs-vue-browser/index.js', //'systemjs-plugin-vue': 'npm:systemjs-plugin-vue/index.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' }, rxjs: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' }, wijmo: { defaultExtension: 'js', } } }); })(this);