Custom Cell Content

The FlexGrid provides a powerful infrastructure for binding cells to data and formatting the cells using CSS. But in some cases that may not be enough. In those situations, use the formatItem event to customize the style or the content presented in each cell. The grid below uses formatItem to format cells with star ratings and sparklines.

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import * as wjGrid from '@grapecity/wijmo.grid'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { // // generate some data var data = [ { rank: 1, title: 'The Wizard of Oz', rating: 4, attendance: getArr(40), revenue: getArr(20) }, { rank: 2, title: 'Citizen Kane', rating: 5, attendance: getArr(40), revenue: getArr(20) }, { rank: 3, title: 'The Godfather', rating: 5, attendance: getArr(40), revenue: getArr(20) }, { rank: 4, title: 'Metropolis', rating: 4, attendance: getArr(40), revenue: getArr(20) }, { rank: 5, title: 'Singing\' in the Rain', rating: 2, attendance: getArr(40), revenue: getArr(20) }, { rank: 6, title: 'Casablanca', rating: 3, attendance: getArr(40), revenue: getArr(20) }, { rank: 7, title: 'Alien', rating: 5, attendance: getArr(40), revenue: getArr(20) }, { rank: 8, title: 'Vertigo', rating: 2, attendance: getArr(40), revenue: getArr(20) }, { rank: 9, title: 'Gone with the Wind', rating: 4, attendance: getArr(40), revenue: getArr(20) }, { rank: 10, title: 'Chinatown', rating: 2, attendance: getArr(40), revenue: getArr(20) } ]; function getArr(len) { var arr = []; for (var i = 0; i < len; i++) { arr.push(Math.round(Math.random() * 100)); } return arr; } // // column properties var theGrid = new wjGrid.FlexGrid('#theGrid', { isReadOnly: true, allowResizing: 'None', alternatingRowStep: 0, autoGenerateColumns: false, columns: [ { binding: 'rank', header: '#', width: 50 }, { binding: 'title', header: 'Title', width: '2*' }, { binding: 'rating', header: 'Rating', align: 'center', cssClass: 'cell-rating', width: '*' }, { binding: 'attendance', header: 'Attendance', cssClass: 'cell-attendance', width: '2*' }, { binding: 'revenue', header: 'Revenue', cssClass: 'cell-revenue', width: '2*' }, ], itemsSource: data, formatItem: function (s, e) { if (e.panel == s.cells) { var item = s.rows[e.row].dataItem; switch (s.columns[e.col].binding) { case 'rating': formatRatingCell(e.cell, item.rating); break; case 'attendance': formatAttendanceCell(e.cell, item.attendance); break; case 'revenue': formatRevenueCell(e.cell, item.revenue); break; } } } }); // function formatRatingCell(cell, rating) { var html = '<div aria-label="rating:' + rating + ' stars">'; for (var i = 0; i < rating; i++) { html += '<span class="glyphicon glyphicon-star"></span>'; } html += '</div>'; cell.innerHTML = html; } function formatAttendanceCell(cell, data) { cell.innerHTML = getSparklines(data); } function formatRevenueCell(cell, data) { cell.innerHTML = getSparkbars(data); } // // // generate sparklines as SVG function getSparklines(data) { var svg = '', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), x1 = 0, y1 = scaleY(data[0], min, max), x2, y2; for (var i = 1; i < data.length; i++) { x2 = Math.round((i) / (data.length - 1) * 100); y2 = scaleY(data[i], min, max); svg += '<line x1=' + x1 + '% y1=' + y1 + '% x2=' + x2 + '% y2=' + y2 + '% />'; x1 = x2; y1 = y2; } return wrapSvg(svg, 'sparklines'); } function getSparkbars(data) { var svg = '', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), base = Math.min(max, Math.max(min, 0)), basey = scaleY(base, min, max), w = Math.round(100 / data.length) - 2, x, y; for (var i = 0; i < data.length; i++) { x = i * Math.round(100 / data.length) + 1; y = scaleY(data[i], min, max); svg += '<rect x=' + x + '% width=' + w + '% y=' + Math.min(y, basey) + '% height=' + Math.abs(y - basey) + '% />'; } svg += '<rect x=0% width=100% height=1 y=' + basey + '% opacity=.5 />'; return wrapSvg(svg, 'sparkbars'); } // function scaleY(value, min, max) { return 100 - Math.round((value - min) / (max - min) * 100); } function wrapSvg(svg, title) { return '<div aria-label="' + title + '" ' + 'style="width:100%;height:100%;box-sizing:border-box;padding:4px">' + '<svg width="100%" height="100%" style="stroke:currentColor;"><g>' + svg + '</g></svg></div>'; } // } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Sparklines</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div class="container-fluid"> <div id="theGrid"> </div> </div> </body> </html> .wj-flexgrid { max-height: 250px; margin: 10px 0; } .cell-rating { color: gold } .cell-attendance:not(.wj-state-selected):not(.wj-state-multi-selected), .cell-revenue:not(.wj-state-selected):not(.wj-state-multi-selected){ color: blue } body { margin-bottom: 20px; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import { Component, enableProdMode, NgModule } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import * as wjcGrid from '@grapecity/wijmo.grid'; import { WjGridModule } from '@grapecity/wijmo.angular2.grid'; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { data: any[]; constructor() { this.data = this._getData(); } initializeGrid(flex: wjcGrid.FlexGrid) { flex.formatItem.addHandler((s: any, e: wjcGrid.FormatItemEventArgs) => { if (e.panel == s.cells) { var item = s.rows[e.row].dataItem; switch (s.columns[e.col].binding) { case 'rating': this._formatRatingCell(e.cell, item.rating); break; case 'attendance': this._formatAttendanceCell(e.cell, item.attendance); break; case 'revenue': this._formatRevenueCell(e.cell, item.revenue); break; } } }); } private _formatRatingCell(cell: HTMLElement, rating: number) { let html = '<div aria-label="rating:' + rating + ' stars">'; for (let i = 0; i < rating; i++) { html += '<span class="glyphicon glyphicon-star"></span>'; } html += '</div>'; cell.innerHTML = html; } private _formatAttendanceCell(cell: HTMLElement, data: number[]) { cell.innerHTML = this._getSparklines(data) } private _formatRevenueCell(cell: HTMLElement, data: number[]) { cell.innerHTML = this._getSparkbars(data) } // generate sparklines as SVG private _getSparklines(data: number[]) { let svg = '', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), x1 = 0, y1 = this._scaleY(data[0], min, max), x2, y2; for (let i = 1; i < data.length; i++) { x2 = Math.round((i) / (data.length - 1) * 100); y2 = this._scaleY(data[i], min, max); svg += '<line x1=' + x1 + '% y1=' + y1 + '% x2=' + x2 + '% y2=' + y2 + '% />'; x1 = x2; y1 = y2; } return this._wrapSvg(svg, 'sparklines'); } private _getSparkbars (data: number[]) { let svg = '', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), base = Math.min(max, Math.max(min, 0)), basey = this._scaleY(base, min, max), w = Math.round(100 / data.length) - 2, x, y; for (let i = 0; i < data.length; i++) { x = i * Math.round(100 / data.length) + 1; y = this._scaleY(data[i], min, max); svg += '<rect x=' + x + '% width=' + w + '% y=' + Math.min(y, basey) + '% height=' + Math.abs(y - basey) + '% />'; } svg += '<rect x=0% width=100% height=1 y=' + basey + '% opacity=.5 />'; return this._wrapSvg(svg, 'sparkbars'); } private _scaleY(value: number, min: number, max: number) { return 100 - Math.round((value - min) / (max - min) * 100); } private _wrapSvg(svg: string, title: string) { return '<div aria-label="' + title + '" ' + 'style="width:100%;height:100%;box-sizing:border-box;padding:4px">' + '<svg width="100%" height="100%" style="stroke:currentColor;"><g>' + svg + '</g></svg></div>'; } private _getData() { return [ { rank: 1, title: 'The Wizard of Oz', rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 2, title: 'Citizen Kane', rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 3, title: 'The Godfather', rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 4, title: 'Metropolis', rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 5, title: 'Singing\' in the Rain', rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 6, title: 'Casablanca', rating: 3, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 7, title: 'Alien', rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 8, title: 'Vertigo', rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 9, title: 'Gone with the Wind', rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 10, title: 'Chinatown', rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) } ] } private _getArr(len: number) { let arr = []; for (let i = 0; i < len; i++) { arr.push(Math.round(Math.random() * 100)); } return arr; } } // @NgModule({ imports: [WjGridModule, BrowserModule], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule { } // enableProdMode(); // Bootstrap application with hash style navigation and global services. platformBrowserDynamic().bootstrapModule(AppModule); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Sparklines</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Polyfills --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.min.js"></script> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.js"></script> <script src="systemjs.config.js"></script> <script> // workaround to load 'rxjs/operators' from the rxjs bundle System.import('rxjs').then(function (m) { System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators)); System.import('./src/app.component'); }); </script> </head> <body> <app-component></app-component> </body> </html> <div class="container-fluid"> <wj-flex-grid #flex [isReadOnly]="true" [allowResizing]="'None'" [alternatingRowStep]="0" (initialized)="initializeGrid(flex)" [(itemsSource)]="data"> <wj-flex-grid-column [binding]="'rank'" [header]="'#'" [width]="50"></wj-flex-grid-column> <wj-flex-grid-column [binding]="'title'" [header]="'Title'" [width]="'2*'"></wj-flex-grid-column> <wj-flex-grid-column [binding]="'rating'" [header]="'Rating'" [align]="'center'" [cssClass]="'cell-rating'" [width]="'*'"></wj-flex-grid-column> <wj-flex-grid-column [binding]="'attendance'" [header]="'Attendance'" [cssClass]="'cell-attendance'" [width]="'2*'"></wj-flex-grid-column> <wj-flex-grid-column [binding]="'revenue'" [header]="'Revenue'" [cssClass]="'cell-revenue'" [width]="'2*'"></wj-flex-grid-column> </wj-flex-grid> </div> .wj-flexgrid { max-height: 250px; margin: 10px 0; } .cell-rating { color: gold } .cell-attendance:not(.wj-state-selected):not(.wj-state-multi-selected), .cell-revenue:not(.wj-state-selected):not(.wj-state-multi-selected){ color: blue } body { margin-bottom: 20px; } <template> <div class="container-fluid"> <wj-flex-grid :isReadOnly="true" :allowResizing="'None'" :alternatingRowStep="0" :initialized="initializeGrid" :itemsSource="data" > <wj-flex-grid-column :binding="'rank'" :header="'#'" :width="50"></wj-flex-grid-column> <wj-flex-grid-column :binding="'title'" :header="'Title'" :width="'2*'"></wj-flex-grid-column> <wj-flex-grid-column :binding="'rating'" :header="'Rating'" :align="'center'" :cssClass="'cell-rating'" :width="'*'" ></wj-flex-grid-column> <wj-flex-grid-column :binding="'attendance'" :header="'Attendance'" :cssClass="'cell-attendance'" :width="'2*'" ></wj-flex-grid-column> <wj-flex-grid-column :binding="'revenue'" :header="'Revenue'" :cssClass="'cell-revenue'" :width="'2*'" ></wj-flex-grid-column> </wj-flex-grid> </div> </template> <script> import "@grapecity/wijmo.styles/wijmo.css"; import "bootstrap.css"; import Vue from "vue"; import "@grapecity/wijmo.vue2.grid"; import * as wjcCore from "@grapecity/wijmo"; let App = Vue.extend({ name: "app", data: function() { return { data: this._getData(200) }; }, methods: { initializeGrid: function(flex) { flex.formatItem.addHandler((s, e) => { if (e.panel == s.cells) { var item = s.rows[e.row].dataItem; switch (s.columns[e.col].binding) { case "rating": this._formatRatingCell(e.cell, item.rating); break; case "attendance": this._formatAttendanceCell(e.cell, item.attendance); break; case "revenue": this._formatRevenueCell(e.cell, item.revenue); break; } } }); }, _formatRatingCell: function(cell, rating) { let html = '<div aria-label="rating:' + rating + ' stars">'; for (let i = 0; i < rating; i++) { html += '<span class="glyphicon glyphicon-star"></span>'; } html += "</div>"; cell.innerHTML = html; }, _formatAttendanceCell: function(cell, data) { cell.innerHTML = this._getSparklines(data); }, _formatRevenueCell: function(cell, data) { cell.innerHTML = this._getSparkbars(data); }, // generate sparklines as SVG _getSparklines: function(data) { let svg = "", min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), x1 = 0, y1 = this._scaleY(data[0], min, max), x2, y2; for (let i = 1; i < data.length; i++) { x2 = Math.round((i / (data.length - 1)) * 100); y2 = this._scaleY(data[i], min, max); svg += "<line x1=" + x1 + "% y1=" + y1 + "% x2=" + x2 + "% y2=" + y2 + "% />"; x1 = x2; y1 = y2; } return this._wrapSvg(svg, "sparklines"); }, _getSparkbars: function(data) { let svg = "", min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), base = Math.min(max, Math.max(min, 0)), basey = this._scaleY(base, min, max), w = Math.round(100 / data.length) - 2, x, y; for (let i = 0; i < data.length; i++) { x = i * Math.round(100 / data.length) + 1; y = this._scaleY(data[i], min, max); svg += "<rect x=" + x + "% width=" + w + "% y=" + Math.min(y, basey) + "% height=" + Math.abs(y - basey) + "% />"; } svg += "<rect x=0% width=100% height=1 y=" + basey + "% opacity=.5 />"; return this._wrapSvg(svg, "sparkbars"); }, _scaleY: function(value, min, max) { return 100 - Math.round(((value - min) / (max - min)) * 100); }, _wrapSvg: function(svg, title) { return ( '<div aria-label="' + title + '" ' + 'style="width:100%;height:100%;box-sizing:border-box;padding:4px">' + '<svg width="100%" height="100%" style="stroke:currentColor;"><g>' + svg + "</g></svg></div>" ); }, _getData: function() { return [ { rank: 1, title: "The Wizard of Oz", rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 2, title: "Citizen Kane", rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 3, title: "The Godfather", rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 4, title: "Metropolis", rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 5, title: "Singing' in the Rain", rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 6, title: "Casablanca", rating: 3, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 7, title: "Alien", rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 8, title: "Vertigo", rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 9, title: "Gone with the Wind", rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 10, title: "Chinatown", rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) } ]; }, _getArr: function(len) { let arr = []; for (let i = 0; i < len; i++) { arr.push(Math.round(Math.random() * 100)); } return arr; } } }); new Vue({ render: h => h(App) }).$mount("#app"); </script> <style> .wj-flexgrid { max-height: 250px; margin: 10px 0; } .cell-rating { color: gold; } .cell-attendance:not(.wj-state-selected):not(.wj-state-multi-selected), .cell-revenue:not(.wj-state-selected):not(.wj-state-multi-selected) { color: blue; } body { margin-bottom: 20px; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AutoComplete</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app.vue'); </script> </head> <body> <div id="app"> </div> </body> </html> import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './app.css'; // import * as React from 'react'; import * as ReactDOM from 'react-dom'; import * as wjGrid from '@grapecity/wijmo.react.grid'; class App extends React.Component { constructor(props) { super(props); this.state = { data: this. getData() }; } render() { return <div className="container-fluid"> <wjGrid.FlexGrid isReadOnly={true} allowResizing="None" alternatingRowStep={1} initialized={this.initializeGrid.bind(this)} itemsSource={this.state.data}> <wjGrid.FlexGridColumn binding="rank" header="#" width={50}></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="title" header="Title" width="2*"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="rating" header="Rating" width="*" align="center" cssClass="cell-rating"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="attendance" header="Attendance" width="2*" cssClass="cell-cell-attendance"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="revenue" header="Revenue" width="2*" cssClass="cell-revenue"></wjGrid.FlexGridColumn> </wjGrid.FlexGrid> </div>; } initializeGrid(flex) { flex.formatItem.addHandler((s, e) => { if (e.panel == s.cells) { var item = s.rows[e.row].dataItem; switch (s.columns[e.col].binding) { case "rating": this._formatRatingCell(e.cell, item.rating); break; case "attendance": this._formatAttendanceCell(e.cell, item.attendance); break; case "revenue": this._formatRevenueCell(e.cell, item.revenue); break; } } }); } _formatRatingCell(cell, rating) { let html = '<div aria-label="rating:' + rating + ' stars">'; for (let i = 0; i < rating; i++) { html += '<span class="glyphicon glyphicon-star"></span>'; } html += "</div>"; cell.innerHTML = html; } _formatAttendanceCell(cell, data) { cell.innerHTML = this._getSparklines(data); } _formatRevenueCell(cell, data) { cell.innerHTML = this._getSparkbars(data); } // generate sparklines as SVG _getSparklines(data) { let svg = "", min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), x1 = 0, y1 = this._scaleY(data[0], min, max), x2, y2; for (let i = 1; i < data.length; i++) { x2 = Math.round((i / (data.length - 1)) * 100); y2 = this._scaleY(data[i], min, max); svg += "<line x1=" + x1 + "% y1=" + y1 + "% x2=" + x2 + "% y2=" + y2 + "% />"; x1 = x2; y1 = y2; } return this._wrapSvg(svg, "sparklines"); } _getSparkbars(data) { let svg = "", min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), base = Math.min(max, Math.max(min, 0)), basey = this._scaleY(base, min, max), w = Math.round(100 / data.length) - 2, x, y; for (let i = 0; i < data.length; i++) { x = i * Math.round(100 / data.length) + 1; y = this._scaleY(data[i], min, max); svg += "<rect x=" + x + "% width=" + w + "% y=" + Math.min(y, basey) + "% height=" + Math.abs(y - basey) + "% />"; } svg += "<rect x=0% width=100% height=1 y=" + basey + "% opacity=.5 />"; return this._wrapSvg(svg, "sparkbars"); } _scaleY(value, min, max) { return 100 - Math.round(((value - min) / (max - min)) * 100); } _wrapSvg(svg, title) { return ('<div aria-label="' + title + '" ' + 'style="width:100%;height:100%;box-sizing:border-box;padding:4px">' + '<svg width="100%" height="100%" style="stroke:currentColor;"><g>' + svg + "</g></svg></div>"); } getData() { return [ { rank: 1, title: "The Wizard of Oz", rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 2, title: "Citizen Kane", rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 3, title: "The Godfather", rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 4, title: "Metropolis", rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 5, title: "Singing' in the Rain", rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 6, title: "Casablanca", rating: 3, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 7, title: "Alien", rating: 5, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 8, title: "Vertigo", rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 9, title: "Gone with the Wind", rating: 4, attendance: this._getArr(40), revenue: this._getArr(20) }, { rank: 10, title: "Chinatown", rating: 2, attendance: this._getArr(40), revenue: this._getArr(20) } ]; } _getArr(len) { let arr = []; for (let i = 0; i < len; i++) { arr.push(Math.round(Math.random() * 100)); } return arr; } } ReactDOM.render(<App />, document.getElementById('app')); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Column Collections</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div id="app"></div> </body> </html> .wj-flexgrid { max-height: 250px; margin: 10px 0; } .cell-rating { color: gold; } .cell-attendance:not(.wj-state-selected):not(.wj-state-multi-selected), .cell-revenue:not(.wj-state-selected):not(.wj-state-multi-selected) { color: blue; } body { margin-bottom: 20px; }