diff --git a/index.html b/index.html index c4e6f8be..9d1edff9 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -
Theme :

\ No newline at end of file +
Theme :

\ No newline at end of file diff --git a/resources/elf-halo-dark.js b/resources/elf-halo-dark.js index ddd5b83d..852fd2ec 100644 --- a/resources/elf-halo-dark.js +++ b/resources/elf-halo-dark.js @@ -12887,7 +12887,7 @@ Recommended fix: /* harmony export */x: () => ( /* binding */VERSION) /* harmony export */ }); - const VERSION = '6.18.0'; + const VERSION = '6.18.1'; /***/ }), @@ -37083,30 +37083,41 @@ Recommended fix: */ DragUI.prototype._grid = null; - /** @public + /** Apply the theme colors to the specified grid after DragUI.initStyles + * @public * @param {Object} grid core grid instance */ DragUI.applyThemeColor = function (grid) { - // This call after onThemeLoaded from extensions initialize - if (!grid || grid._dragUIStyles) { return; } if (DragUI._styles) { grid._dragUIStyles = true; // Prevent loading the same style twice injectCss(DragUI._styles, grid.getElement()); - } else { - // TODO : Handle if can not load DragUI._styles try to set new DragUI._styles - // Warning: This process have to use ElfUtil.getThemeColors() that async process for Backward compatability. - // When use async process, then it can be load theme multiple times. } + // TO_DO : Handle if can not load DragUI._styles try to set new DragUI._styles + // Warning: This process have to use ElfUtil.getThemeColors() that async process for Backward compatability. + // When use async process, then it can be load theme multiple times. }; - /** @public + /** Deprecated in favor of DragUI.initStyles() + * @public * @param {Object} colors */ DragUI.prototype.onThemeLoaded = function (colors) { + DragUI.initStyles(colors); + }; + + /** WARNING: This method should be called after the theme has been loaded in order to initialize with the correct colors. + * @public + * @function + * @param {Object=} colors + */ + DragUI.initStyles = function (colors) { if (!DragUI._styles) { + if (!colors) { + colors = es6_ElfUtil.getColors(); + } let ElfVersion = es6_ElfUtil.getElfVersion(); let cursor = "grabbing"; if (ElfVersion < 3) { @@ -37265,15 +37276,14 @@ Recommended fix: * @param {ColumnDraggingPlugin~Options=} options * @extends {GridPlugin} */ - var ColumnDraggingPlugin = function (options) { - var t = this; + let ColumnDraggingPlugin = function (options) { + let t = this; t._onMouseUp = t._onMouseUp.bind(t); t._onMouseDown = t._onMouseDown.bind(t); t._onDrag = t._onDrag.bind(t); t._onDragStart = t._onDragStart.bind(t); t._onDragEnd = t._onDragEnd.bind(t); t._onDragPulse = t._onDragPulse.bind(t); - t._onThemeLoaded = t._onThemeLoaded.bind(t); t._hosts = []; t._guideline = document.createElement("div"); t._dragBox = document.createElement("div"); @@ -37427,20 +37437,13 @@ Recommended fix: dragBox: this._dragBox, dragBoxIcon: this._dragBoxIcon }); - - // Share dragging styles - if (DragUI.stylePromise) { - DragUI.applyThemeColor(host); - } else { - DragUI.stylePromise = ElfUtil.getThemeColors(); - DragUI.stylePromise.then(this._onThemeLoaded).catch(this._onThemeLoaded); - } + ElfUtil.getThemeColors().then(ColumnDraggingPlugin._onThemeLoaded.bind(null, host)).catch(ColumnDraggingPlugin._onThemeLoaded.bind(null, host)); }; /** @public * @param {Object=} host core grid instance */ ColumnDraggingPlugin.prototype.unload = function (host) { - var at = this._hosts.indexOf(host); + let at = this._hosts.indexOf(host); if (at < 0) { return; } @@ -37456,22 +37459,21 @@ Recommended fix: }; /** @private + * @function + * @param {Object} grid Core grid instance */ - ColumnDraggingPlugin.prototype._onThemeLoaded = function () { + ColumnDraggingPlugin._onThemeLoaded = function (grid) { if (!ColumnDraggingPlugin._styles) { let styles = [".multi-column-drag-indicator .section.title .cover-layer .column-bound.selection-bound ", ["border-top: var(--grid-drag-indicator);", "border-right: var(--grid-drag-indicator);", "border-left: var(--grid-drag-indicator);"], ".multi-column-drag-indicator .sections .cover-layer .column-bound.selection-bound ", ["border-right: var(--grid-drag-indicator);", "border-left: var(--grid-drag-indicator);", "border-bottom: var(--grid-drag-indicator);"]]; ColumnDraggingPlugin._styles = prettifyCss(styles); } - let colors = ElfUtil.getColors(); - this._dragUI.onThemeLoaded(colors); // TODO : onThemeLoaded should be static function like DragUI.applyThemeColor - for (let i = this._hosts.length; --i >= 0;) { - let host = this._hosts[i]; - ColumnDraggingPlugin._applyThemeColor(host); - DragUI.applyThemeColor(host); - } + DragUI.initStyles(); + ColumnDraggingPlugin._applyThemeColor(grid); + DragUI.applyThemeColor(grid); }; + /** @private - * @param {Object} grid core grid instance + * @param {Object} grid Core grid instance */ ColumnDraggingPlugin._applyThemeColor = function (grid) { if (!grid || grid._columnDraggingStyles) { @@ -37490,14 +37492,14 @@ Recommended fix: if (!options) { return; } - var noColumnDragging = options["noColumnDragging"]; + let noColumnDragging = options["noColumnDragging"]; if (noColumnDragging == null && options["columnReorder"] != null) { noColumnDragging = !options["columnReorder"]; } if (noColumnDragging != null) { this._disabled = noColumnDragging ? true : false; } - var extOptions = options.columnDragging; + let extOptions = options.columnDragging; if (!extOptions) { return; } @@ -37519,13 +37521,13 @@ Recommended fix: * @return {!Object} */ ColumnDraggingPlugin.prototype.getConfigObject = function (gridOptions) { - var obj = gridOptions || {}; + let obj = gridOptions || {}; if (this._disabled) { obj.noColumnDragging = true; } - var extOptions = obj.columnDragging; + let extOptions = obj.columnDragging; if (!extOptions) { - extOptions = obj.columnDragging = {}; + extOptions = obj.columnDragging = {}; // TO_DO: This is unnecessary } return obj; }; @@ -37572,9 +37574,9 @@ Recommended fix: * @return {boolean} */ ColumnDraggingPlugin.prototype._isAllowed = function (colIndex) { - var host = this._clickedGrid || this._hosts[0]; + let host = this._clickedGrid || this._hosts[0]; if (host) { - var stationaryIndex = host.getStationaryColumnIndex(); + let stationaryIndex = host.getStationaryColumnIndex(); if (stationaryIndex < 0) { return true; } @@ -37655,7 +37657,7 @@ Recommended fix: if (this._timerId) { return; // Drag timer is already start } - var host = this.getRelativeGrid(e); + let host = this.getRelativeGrid(e); if (!host) { return; // Given event should be within grid element } @@ -37663,22 +37665,22 @@ Recommended fix: if (this._pos["hit"] === false) { return; // Only start dragging when mouse is down on the grid } - var section = this._pos["section"]; + let section = this._pos["section"]; if (!section) { return; // The section that is not in the target section list cannot be dragged } else if (this._pos["sectionType"] !== "title") { return; // Sections other than title section cannot be dragged by default } - var colIndex = this._pos["colIndex"]; + let colIndex = this._pos["colIndex"]; if (!this._isAllowed(colIndex)) { return; // The column cannot be dragged } if (this._lockFrozen && host.isPinnedColumn(colIndex)) { return; // If the lock frag is on, frozen columns cannot be dragged } - var rowIndex = this._pos["rowIndex"]; // rowIndex may not exist - var movableBorder = this._findMoveableBorder(colIndex, rowIndex - 1, section); - var movingColumns = this._getSpan(colIndex, rowIndex, section); + let rowIndex = this._pos["rowIndex"]; // rowIndex may not exist + let movableBorder = this._findMoveableBorder(colIndex, rowIndex - 1, section); + let movingColumns = this._getSpan(colIndex, rowIndex, section); this._clickedGrid = host; this._clickedSection = section; this._clickedRow = rowIndex; @@ -37771,11 +37773,11 @@ Recommended fix: window.addEventListener("mousemove", this._onDrag, false); // TODO: support touch operation window.addEventListener("mouseup", this._onDragEnd, true); - var host = this._clickedGrid; - var height = host.getHeight(); - var sectionBound = this._clickedSection.getBoundingClientRect(); - var clickedCellBound = this._clickedSection.getCell(this._startColumn, this._clickedRow).getBoundingClientRect(); - var gridElem = host.getElement(); + let host = this._clickedGrid; + let height = host.getHeight(); + let sectionBound = this._clickedSection.getBoundingClientRect(); + let clickedCellBound = this._clickedSection.getCell(this._startColumn, this._clickedRow).getBoundingClientRect(); + let gridElem = host.getElement(); this._guideline.style.top = clickedCellBound.top - sectionBound.top + "px"; this._guideline.style.height = height - 1 + "px"; @@ -37786,10 +37788,10 @@ Recommended fix: gridElem.appendChild(this._guideline); if (this._dragBoxRenderer) { // For custom drag box rendering - var arg = cloneObject(e); // TODO: Check if cloning is necessary - var id = this.getColumnId(this._startColumn); - var index = this.getColumnIndex(id); - var field = this._getField(this._startColumn); + let arg = cloneObject(e); // TODO: Check if cloning is necessary + let id = this.getColumnId(this._startColumn); + let index = this.getColumnIndex(id); + let field = this._getField(this._startColumn); arg.dragBox = this._dragBox; arg.columnData = { index: index, @@ -37812,7 +37814,7 @@ Recommended fix: } else if (this._scrollStep > 400) { this._scrollStep = 400; } - var scrollbar = host.getHScrollbar(); + let scrollbar = host.getHScrollbar(); this._cacheLeft = scrollbar.getLeft() + 20; this._cacheWidth = scrollbar.getLeft() + scrollbar.getWidth() - 20; this._dragPulseId = window.setInterval(this._onDragPulse, 150); // Start pulse @@ -37831,7 +37833,7 @@ Recommended fix: if (!host || host !== this._clickedGrid) { return; } - var colIndex = this._pos["colIndex"]; + let colIndex = this._pos["colIndex"]; if (colIndex >= this._leftMovableBorder && colIndex <= this._rightMovableBorder && this._isAllowed(colIndex) && !(this._lockFrozen && host.isPinnedColumn(colIndex))) { e.dragBox = this._dragBox; this._renderGuideline(); @@ -37852,7 +37854,7 @@ Recommended fix: document.body.classList.remove("tr-dragging"); // document.body.classList.remove("tr-move-cursor"); this._dimCol(false); - var pn = this._guideline.parentNode; + let pn = this._guideline.parentNode; if (pn) { pn.removeChild(this._guideline); } @@ -37868,10 +37870,10 @@ Recommended fix: window.clearInterval(this._dragPulseId); this._dragPulseId = 0; } - var destPos = this._pos; + let destPos = this._pos; this._pos = null; preventDefault(e); - var operationCancelled = false; + let operationCancelled = false; if (destPos["cancel"]) { operationCancelled = true; } @@ -37888,7 +37890,7 @@ Recommended fix: this._destColumn < 0 || !this._isAllowed(this._destColumn) || this._destColumn >= this._startColumn && this._destColumn <= this._endColumn) { operationCancelled = true; } - var arg = null; + let arg = null; if (!operationCancelled) { arg = { "startColumnIndex": this._startColumn, @@ -37940,13 +37942,14 @@ Recommended fix: let colList = []; let csp = this._getPlugin("ColumnStackPlugin"); let stackId, groupId; + let i; if (srcCount === 1) { if (csp) { stackId = csp.getStackId(this._startColumn); } let cgp = this._getPlugin("ColumnGroupingPlugin"); if (cgp) { - var cellInfo = cgp.getCellInfo(this._startPos); + let cellInfo = cgp.getCellInfo(this._startPos); groupId = cellInfo["groupId"] || cellInfo["columnId"]; } if (stackId && this._startColumn === this._endColumn) { @@ -37954,15 +37957,14 @@ Recommended fix: } else if (groupId) { cgp.moveGroup(groupId, destColumnIndex); } else { - for (let i = this._startColumn; i <= this._endColumn; i++) { + for (i = this._startColumn; i <= this._endColumn; i++) { colList.push(i); } } } else { let stacking = {}; // Object to optimize call column stack api repeatly - for (let i = 0; i < srcCount; i++) { + for (i = 0; i < srcCount; i++) { let srcIdx = srcColIndices[i]; - let srcId = this.getColumnId(srcIdx); if (csp) { stackId = csp.getStackId(srcIdx); } @@ -37974,12 +37976,13 @@ Recommended fix: colList.push(colId); } } else { + let srcId = this.getColumnId(srcIdx); colList.push(srcId); // Normal case } } } - for (let i = this._hosts.length; --i >= 0;) { - var host = this._hosts[i]; + for (i = this._hosts.length; --i >= 0;) { + let host = this._hosts[i]; host.reorderColumns(colList, destColumnIndex); } }; @@ -37991,19 +37994,19 @@ Recommended fix: return; } this._dispatch("dragInterval", this._pos); - var host = this._clickedGrid; + let host = this._clickedGrid; if (!host || !host.getHScrollbar().isActive()) { return; } - var x = this._pos["x"]; - var scrollVal = 0; + let x = this._pos["x"]; + let scrollVal = 0; if (x < this._cacheLeft) { scrollVal = -Math.floor(this._scrollStep * (0.8 + Math.random())); } else if (x > this._cacheWidth) { scrollVal = Math.floor(this._scrollStep * (0.8 + Math.random())); } - var len = this._hosts ? this._hosts.length : 0; - for (var i = 0; i < len; ++i) { + let len = this._hosts ? this._hosts.length : 0; + for (let i = 0; i < len; ++i) { this._hosts[i].scrollRight(scrollVal); } }; @@ -38025,7 +38028,7 @@ Recommended fix: * @return {!Object} */ ColumnDraggingPlugin.prototype._getSpan = function (colIndex, row, section) { - var cellSpan = section.getCellColSpan(colIndex, row); + let cellSpan = section.getCellColSpan(colIndex, row); if (cellSpan <= 0) { // The specified cell is being occupied colIndex += cellSpan; // Convert the given negative index to the spanning cell @@ -38050,7 +38053,7 @@ Recommended fix: "right": section.getColumnCount() - 1 }; } - var span = this._getSpan(col, row, section); + let span = this._getSpan(col, row, section); if (span["right"] >= span["left"]) { return span; } else { @@ -38061,27 +38064,27 @@ Recommended fix: * @private */ ColumnDraggingPlugin.prototype._renderGuideline = function () { - var colIndex = this._pos["colIndex"]; + let colIndex = this._pos["colIndex"]; if (colIndex == null || colIndex < 0) { // undefined, null or negative number return; } - var currentSpan = this._getSpan(colIndex, this._clickedRow, this._clickedSection); - var colStart = currentSpan["left"]; // This can be different from colIndex - var colEnd = currentSpan["right"]; - var colLeft = this._clickedGrid.getColumnLeft(colStart); - var colWidth = 0; - for (var i = colStart; i <= colEnd; ++i) { + let currentSpan = this._getSpan(colIndex, this._clickedRow, this._clickedSection); + let colStart = currentSpan["left"]; // This can be different from colIndex + let colEnd = currentSpan["right"]; + let colLeft = this._clickedGrid.getColumnLeft(colStart); + let colWidth = 0; + for (let i = colStart; i <= colEnd; ++i) { colWidth += this._clickedGrid.getColumnWidth(i); } - var rightHand = this._pos["x"] > colLeft + colWidth / 2; - var destColumn = rightHand ? colEnd + 1 : colStart; - var csp = this._getPlugin("ColumnStackPlugin"); + let rightHand = this._pos["x"] > colLeft + colWidth / 2; + let destColumn = rightHand ? colEnd + 1 : colStart; + let csp = this._getPlugin("ColumnStackPlugin"); if (csp) { - var stackId = csp.getStackId(destColumn); + let stackId = csp.getStackId(destColumn); if (stackId) { - var members = csp.getStackMemberIndices(stackId); - var memberCount = members.length; + let members = csp.getStackMemberIndices(stackId); + let memberCount = members.length; if (members && memberCount) { destColumn = rightHand ? members[memberCount - 1] + 1 : members[0]; } @@ -38106,9 +38109,9 @@ Recommended fix: * @param {boolean} inOut */ ColumnDraggingPlugin.prototype._dimCol = function (inOut) { - var host = this._clickedGrid; - var titleCell = host.getSection("title").getColumn(this._startColumn).getCell(this._clickedRow); - var titleCellEl = titleCell.getElement(); + let host = this._clickedGrid; + let titleCell = host.getSection("title").getColumn(this._startColumn).getCell(this._clickedRow); + let titleCellEl = titleCell.getElement(); if (inOut) { titleCellEl.classList.add("drag-indicator"); } else { @@ -66451,7 +66454,6 @@ Recommended fix: t._onDragStart = t._onDragStart.bind(t); t._onMouseMove = t._onMouseMove.bind(t); t._onDragEnd = t._onDragEnd.bind(t); - t._onThemeLoaded = t._onThemeLoaded.bind(t); t._onJETDrop = t._onJETDrop.bind(t); t._onJETDragOver = t._onJETDragOver.bind(t); t._delayStart = t._delayStart.bind(t); @@ -66606,15 +66608,6 @@ Recommended fix: */ RowDraggingPlugin.prototype._entryPoint = ""; - /** Applied theme color in row dragging and dragUI - * @private - * @param {Object} host core grid instance - */ - let _applyStyles = function (host) { - RowDraggingPlugin._applyThemeColor(host); - DragUI.applyThemeColor(host); - }; - /** Prevent built-in config * @public * @ignore @@ -66665,14 +66658,7 @@ Recommended fix: dragBox: this._dragBox, dragBoxIcon: this._dragBoxIcon }); - - // Share dragging styles - if (!DragUI.stylePromise) { - DragUI.stylePromise = ElfUtil.getThemeColors(); - DragUI.stylePromise.then(this._onThemeLoaded).catch(this._onThemeLoaded); - } - // TODO: Create a manager to manage styles. Currently, we have to use setTimeout to wait for an element to be created before applying styles - setTimeout(_applyStyles.bind(this, host), 0); + ElfUtil.getThemeColors().then(RowDraggingPlugin._onThemeLoaded.bind(null, host)).catch(RowDraggingPlugin._onThemeLoaded.bind(null, host)); // In case of lazy loading // host.getAllSections("content").forEach(this._registerSection); @@ -66707,17 +66693,17 @@ Recommended fix: }; /** @private + * @function + * @param {Object} grid Core grid instance */ - RowDraggingPlugin.prototype._onThemeLoaded = function () { + RowDraggingPlugin._onThemeLoaded = function (grid) { if (!RowDraggingPlugin._styles) { let styles = [":host .row-dragging .cover-layer .selection-bound", ["border: var(--grid-drag-indicator)"], ":host .row-dragging .tr-lg .cell.selected-row", ["background-color: unset;"]]; RowDraggingPlugin._styles = prettifyCss(styles); } - let colors = ElfUtil.getColors(); - this._dragUI.onThemeLoaded(colors); // TODO : onThemeLoaded should be static function like DragUI.applyThemeColor - for (let i = this._hosts.length; --i >= 0;) { - _applyStyles(this._hosts[i]); - } + DragUI.initStyles(); + RowDraggingPlugin._applyThemeColor(grid); + DragUI.applyThemeColor(grid); }; /** @private * @param {Object} grid core grid instance @@ -172260,7 +172246,7 @@ Recommended fix: ; // CONCATENATED MODULE: ./public/lib/grid/index.js window.EFX_GRID = { - version: "6.0.149" + version: "6.0.150" }; ; // CONCATENATED MODULE: ./public/lib/grid/themes/halo/dark/efx-grid.js @@ -180165,7 +180151,7 @@ Recommended fix: dispatchEvent(new CustomEvent('ef.nativeStyles.define', { detail: { name: 'html', - styles: 'html{height:100%;touch-action:manipulation;-webkit-tap-highlight-color:transparent;scrollbar-face-color:#595959;scrollbar-shadow-color:#595959;scrollbar-highlight-color:#595959;scrollbar-arrow-color:#595959;scrollbar-track-color:#1a1a1a;scrollbar-3dlight-color:#1a1a1a;scrollbar-darkshadow-color:#1a1a1a;--color-scheme-primary:#334BFF;--color-scheme-secondary:#6678FF;--color-scheme-tertiary:#333333;--color-scheme-complementary:#FFFFFF;--color-scheme-negative:#F5475B;--color-scheme-neutral:#CCCCCC;--color-scheme-positive:#39C46E;--color-scheme-tickup:#39C46E;--color-scheme-tickdown:#F5475B;--color-scheme-ticktext:#0D0D0D;--theme-name:\'halo-theme\';--theme-version:\'6.8.1\'}html[movement-color-profile=asian1]{--color-scheme-negative:#39C46E;--color-scheme-neutral:#CCCCCC;--color-scheme-positive:#F5475B;--color-scheme-tickup:#F5475B;--color-scheme-tickdown:#39C46E}html[movement-color-profile=asian2]{--color-scheme-negative:#F5475B;--color-scheme-neutral:#39C46E;--color-scheme-positive:#00D0D4;--color-scheme-tickup:#FFC800;--color-scheme-tickdown:#F5475B}html[movement-color-profile=european]{--color-scheme-negative:#F5475B;--color-scheme-neutral:#39C46E;--color-scheme-positive:#00D0D4;--color-scheme-tickup:#39C46E;--color-scheme-tickdown:#F5475B}::-moz-selection{color:#fff;background:#334bff}::selection{color:#fff;background:#334bff}::-webkit-scrollbar-corner{background:0 0}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:#595959;border-radius:0;border:1px solid transparent}::-webkit-scrollbar-thumb:hover{background:#1429bd}::-webkit-scrollbar-thumb:active{background:#0f1e8a}::-webkit-scrollbar-track{background:#1a1a1a}::-webkit-scrollbar-thumb:horizontal{background-size:auto 6px;background-repeat:repeat-x;background-image:linear-gradient(to bottom,#595959,#595959);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:horizontal:hover{background-image:linear-gradient(to bottom,#1429bd,#1429bd);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:horizontal:active{background-image:linear-gradient(to bottom,#0f1e8a,#0f1e8a);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical{background-size:6px auto;background-repeat:repeat-y;background-image:linear-gradient(to right,#595959,#595959);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical:hover{background-image:linear-gradient(to right,#1429bd,#1429bd);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical:active{background-image:linear-gradient(to right,#0f1e8a,#0f1e8a);background-color:transparent;background-position:center}::-webkit-scrollbar-track:horizontal{border-top:1px solid #0d0d0d;border-bottom:1px solid #0d0d0d}::-webkit-scrollbar-track:vertical{border-left:1px solid #0d0d0d;border-right:1px solid #0d0d0d}::-webkit-scrollbar-button{background:0 0/1px 2px no-repeat #1a1a1a;height:16px;width:16px;display:none;border:1px solid #0d0d0d}::-webkit-scrollbar-button:end:decrement,::-webkit-scrollbar-button:start:increment{display:none}::-webkit-scrollbar-button:hover{background-color:#1429bd;border:1px solid #1429bd}::-webkit-scrollbar-button:active{background-color:#0f1e8a;border:1px solid #0d0d0d}::-webkit-scrollbar-button:horizontal{background-size:2px 1px}::-webkit-scrollbar-button:vertical:start:decrement{border-bottom-color:#0d0d0d;background-image:linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px}::-webkit-scrollbar-button:vertical:start:decrement:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px;border-bottom-color:#1429bd}::-webkit-scrollbar-button:vertical:start:decrement:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px;border-bottom-color:#0d0d0d}::-webkit-scrollbar-button:vertical:end:increment{border-top-color:#0d0d0d;background-image:linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px}::-webkit-scrollbar-button:vertical:end:increment:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px;border-top-color:#1429bd}::-webkit-scrollbar-button:vertical:end:increment:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px;border-top-color:#0d0d0d}::-webkit-scrollbar-button:horizontal:start:decrement{border-right-color:#0d0d0d;background-image:linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px}::-webkit-scrollbar-button:horizontal:start:decrement:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px;border-right-color:#1429bd}::-webkit-scrollbar-button:horizontal:start:decrement:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px;border-right-color:#0d0d0d}::-webkit-scrollbar-button:horizontal:end:increment{border-left-color:#0d0d0d;background-image:linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px}::-webkit-scrollbar-button:horizontal:end:increment:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px;border-left-color:#1429bd}::-webkit-scrollbar-button:horizontal:end:increment:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px;border-left-color:#0d0d0d}@supports not selector(::-webkit-scrollbar){html{scrollbar-color:#595959 #1a1a1a;scrollbar-width:thin;scrollbar-width:auto}}' + styles: 'html{height:100%;touch-action:manipulation;-webkit-tap-highlight-color:transparent;scrollbar-face-color:#595959;scrollbar-shadow-color:#595959;scrollbar-highlight-color:#595959;scrollbar-arrow-color:#595959;scrollbar-track-color:#1a1a1a;scrollbar-3dlight-color:#1a1a1a;scrollbar-darkshadow-color:#1a1a1a;--color-scheme-primary:#334BFF;--color-scheme-secondary:#6678FF;--color-scheme-tertiary:#333333;--color-scheme-complementary:#FFFFFF;--color-scheme-negative:#F5475B;--color-scheme-neutral:#CCCCCC;--color-scheme-positive:#39C46E;--color-scheme-tickup:#39C46E;--color-scheme-tickdown:#F5475B;--color-scheme-ticktext:#0D0D0D;--theme-name:\'halo-theme\';--theme-version:\'6.9.0\'}html[movement-color-profile=asian1]{--color-scheme-negative:#39C46E;--color-scheme-neutral:#CCCCCC;--color-scheme-positive:#F5475B;--color-scheme-tickup:#F5475B;--color-scheme-tickdown:#39C46E}html[movement-color-profile=asian2]{--color-scheme-negative:#F5475B;--color-scheme-neutral:#39C46E;--color-scheme-positive:#00D0D4;--color-scheme-tickup:#FFC800;--color-scheme-tickdown:#F5475B}html[movement-color-profile=european]{--color-scheme-negative:#F5475B;--color-scheme-neutral:#39C46E;--color-scheme-positive:#00D0D4;--color-scheme-tickup:#39C46E;--color-scheme-tickdown:#F5475B}::-moz-selection{color:#fff;background:#334bff}::selection{color:#fff;background:#334bff}::-webkit-scrollbar-corner{background:0 0}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:#595959;border-radius:0;border:1px solid transparent}::-webkit-scrollbar-thumb:hover{background:#1429bd}::-webkit-scrollbar-thumb:active{background:#0f1e8a}::-webkit-scrollbar-track{background:#1a1a1a}::-webkit-scrollbar-thumb:horizontal{background-size:auto 6px;background-repeat:repeat-x;background-image:linear-gradient(to bottom,#595959,#595959);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:horizontal:hover{background-image:linear-gradient(to bottom,#1429bd,#1429bd);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:horizontal:active{background-image:linear-gradient(to bottom,#0f1e8a,#0f1e8a);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical{background-size:6px auto;background-repeat:repeat-y;background-image:linear-gradient(to right,#595959,#595959);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical:hover{background-image:linear-gradient(to right,#1429bd,#1429bd);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical:active{background-image:linear-gradient(to right,#0f1e8a,#0f1e8a);background-color:transparent;background-position:center}::-webkit-scrollbar-track:horizontal{border-top:1px solid #0d0d0d;border-bottom:1px solid #0d0d0d}::-webkit-scrollbar-track:vertical{border-left:1px solid #0d0d0d;border-right:1px solid #0d0d0d}::-webkit-scrollbar-button{background:0 0/1px 2px no-repeat #1a1a1a;height:16px;width:16px;display:none;border:1px solid #0d0d0d}::-webkit-scrollbar-button:end:decrement,::-webkit-scrollbar-button:start:increment{display:none}::-webkit-scrollbar-button:hover{background-color:#1429bd;border:1px solid #1429bd}::-webkit-scrollbar-button:active{background-color:#0f1e8a;border:1px solid #0d0d0d}::-webkit-scrollbar-button:horizontal{background-size:2px 1px}::-webkit-scrollbar-button:vertical:start:decrement{border-bottom-color:#0d0d0d;background-image:linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px}::-webkit-scrollbar-button:vertical:start:decrement:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px;border-bottom-color:#1429bd}::-webkit-scrollbar-button:vertical:start:decrement:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px;border-bottom-color:#0d0d0d}::-webkit-scrollbar-button:vertical:end:increment{border-top-color:#0d0d0d;background-image:linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px}::-webkit-scrollbar-button:vertical:end:increment:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px;border-top-color:#1429bd}::-webkit-scrollbar-button:vertical:end:increment:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px;border-top-color:#0d0d0d}::-webkit-scrollbar-button:horizontal:start:decrement{border-right-color:#0d0d0d;background-image:linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px}::-webkit-scrollbar-button:horizontal:start:decrement:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px;border-right-color:#1429bd}::-webkit-scrollbar-button:horizontal:start:decrement:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px;border-right-color:#0d0d0d}::-webkit-scrollbar-button:horizontal:end:increment{border-left-color:#0d0d0d;background-image:linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc),linear-gradient(#ccc,#ccc);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px}::-webkit-scrollbar-button:horizontal:end:increment:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px;border-left-color:#1429bd}::-webkit-scrollbar-button:horizontal:end:increment:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px;border-left-color:#0d0d0d}@supports not selector(::-webkit-scrollbar){html{scrollbar-color:#595959 #1a1a1a;scrollbar-width:thin;scrollbar-width:auto}}' } })); ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/halo-theme/dark/input.js diff --git a/resources/elf-halo-light.js b/resources/elf-halo-light.js index d3613801..aa532536 100644 --- a/resources/elf-halo-light.js +++ b/resources/elf-halo-light.js @@ -12887,7 +12887,7 @@ Recommended fix: /* harmony export */x: () => ( /* binding */VERSION) /* harmony export */ }); - const VERSION = '6.18.0'; + const VERSION = '6.18.1'; /***/ }), @@ -37083,30 +37083,41 @@ Recommended fix: */ DragUI.prototype._grid = null; - /** @public + /** Apply the theme colors to the specified grid after DragUI.initStyles + * @public * @param {Object} grid core grid instance */ DragUI.applyThemeColor = function (grid) { - // This call after onThemeLoaded from extensions initialize - if (!grid || grid._dragUIStyles) { return; } if (DragUI._styles) { grid._dragUIStyles = true; // Prevent loading the same style twice injectCss(DragUI._styles, grid.getElement()); - } else { - // TODO : Handle if can not load DragUI._styles try to set new DragUI._styles - // Warning: This process have to use ElfUtil.getThemeColors() that async process for Backward compatability. - // When use async process, then it can be load theme multiple times. } + // TO_DO : Handle if can not load DragUI._styles try to set new DragUI._styles + // Warning: This process have to use ElfUtil.getThemeColors() that async process for Backward compatability. + // When use async process, then it can be load theme multiple times. }; - /** @public + /** Deprecated in favor of DragUI.initStyles() + * @public * @param {Object} colors */ DragUI.prototype.onThemeLoaded = function (colors) { + DragUI.initStyles(colors); + }; + + /** WARNING: This method should be called after the theme has been loaded in order to initialize with the correct colors. + * @public + * @function + * @param {Object=} colors + */ + DragUI.initStyles = function (colors) { if (!DragUI._styles) { + if (!colors) { + colors = es6_ElfUtil.getColors(); + } let ElfVersion = es6_ElfUtil.getElfVersion(); let cursor = "grabbing"; if (ElfVersion < 3) { @@ -37265,15 +37276,14 @@ Recommended fix: * @param {ColumnDraggingPlugin~Options=} options * @extends {GridPlugin} */ - var ColumnDraggingPlugin = function (options) { - var t = this; + let ColumnDraggingPlugin = function (options) { + let t = this; t._onMouseUp = t._onMouseUp.bind(t); t._onMouseDown = t._onMouseDown.bind(t); t._onDrag = t._onDrag.bind(t); t._onDragStart = t._onDragStart.bind(t); t._onDragEnd = t._onDragEnd.bind(t); t._onDragPulse = t._onDragPulse.bind(t); - t._onThemeLoaded = t._onThemeLoaded.bind(t); t._hosts = []; t._guideline = document.createElement("div"); t._dragBox = document.createElement("div"); @@ -37427,20 +37437,13 @@ Recommended fix: dragBox: this._dragBox, dragBoxIcon: this._dragBoxIcon }); - - // Share dragging styles - if (DragUI.stylePromise) { - DragUI.applyThemeColor(host); - } else { - DragUI.stylePromise = ElfUtil.getThemeColors(); - DragUI.stylePromise.then(this._onThemeLoaded).catch(this._onThemeLoaded); - } + ElfUtil.getThemeColors().then(ColumnDraggingPlugin._onThemeLoaded.bind(null, host)).catch(ColumnDraggingPlugin._onThemeLoaded.bind(null, host)); }; /** @public * @param {Object=} host core grid instance */ ColumnDraggingPlugin.prototype.unload = function (host) { - var at = this._hosts.indexOf(host); + let at = this._hosts.indexOf(host); if (at < 0) { return; } @@ -37456,22 +37459,21 @@ Recommended fix: }; /** @private + * @function + * @param {Object} grid Core grid instance */ - ColumnDraggingPlugin.prototype._onThemeLoaded = function () { + ColumnDraggingPlugin._onThemeLoaded = function (grid) { if (!ColumnDraggingPlugin._styles) { let styles = [".multi-column-drag-indicator .section.title .cover-layer .column-bound.selection-bound ", ["border-top: var(--grid-drag-indicator);", "border-right: var(--grid-drag-indicator);", "border-left: var(--grid-drag-indicator);"], ".multi-column-drag-indicator .sections .cover-layer .column-bound.selection-bound ", ["border-right: var(--grid-drag-indicator);", "border-left: var(--grid-drag-indicator);", "border-bottom: var(--grid-drag-indicator);"]]; ColumnDraggingPlugin._styles = prettifyCss(styles); } - let colors = ElfUtil.getColors(); - this._dragUI.onThemeLoaded(colors); // TODO : onThemeLoaded should be static function like DragUI.applyThemeColor - for (let i = this._hosts.length; --i >= 0;) { - let host = this._hosts[i]; - ColumnDraggingPlugin._applyThemeColor(host); - DragUI.applyThemeColor(host); - } + DragUI.initStyles(); + ColumnDraggingPlugin._applyThemeColor(grid); + DragUI.applyThemeColor(grid); }; + /** @private - * @param {Object} grid core grid instance + * @param {Object} grid Core grid instance */ ColumnDraggingPlugin._applyThemeColor = function (grid) { if (!grid || grid._columnDraggingStyles) { @@ -37490,14 +37492,14 @@ Recommended fix: if (!options) { return; } - var noColumnDragging = options["noColumnDragging"]; + let noColumnDragging = options["noColumnDragging"]; if (noColumnDragging == null && options["columnReorder"] != null) { noColumnDragging = !options["columnReorder"]; } if (noColumnDragging != null) { this._disabled = noColumnDragging ? true : false; } - var extOptions = options.columnDragging; + let extOptions = options.columnDragging; if (!extOptions) { return; } @@ -37519,13 +37521,13 @@ Recommended fix: * @return {!Object} */ ColumnDraggingPlugin.prototype.getConfigObject = function (gridOptions) { - var obj = gridOptions || {}; + let obj = gridOptions || {}; if (this._disabled) { obj.noColumnDragging = true; } - var extOptions = obj.columnDragging; + let extOptions = obj.columnDragging; if (!extOptions) { - extOptions = obj.columnDragging = {}; + extOptions = obj.columnDragging = {}; // TO_DO: This is unnecessary } return obj; }; @@ -37572,9 +37574,9 @@ Recommended fix: * @return {boolean} */ ColumnDraggingPlugin.prototype._isAllowed = function (colIndex) { - var host = this._clickedGrid || this._hosts[0]; + let host = this._clickedGrid || this._hosts[0]; if (host) { - var stationaryIndex = host.getStationaryColumnIndex(); + let stationaryIndex = host.getStationaryColumnIndex(); if (stationaryIndex < 0) { return true; } @@ -37655,7 +37657,7 @@ Recommended fix: if (this._timerId) { return; // Drag timer is already start } - var host = this.getRelativeGrid(e); + let host = this.getRelativeGrid(e); if (!host) { return; // Given event should be within grid element } @@ -37663,22 +37665,22 @@ Recommended fix: if (this._pos["hit"] === false) { return; // Only start dragging when mouse is down on the grid } - var section = this._pos["section"]; + let section = this._pos["section"]; if (!section) { return; // The section that is not in the target section list cannot be dragged } else if (this._pos["sectionType"] !== "title") { return; // Sections other than title section cannot be dragged by default } - var colIndex = this._pos["colIndex"]; + let colIndex = this._pos["colIndex"]; if (!this._isAllowed(colIndex)) { return; // The column cannot be dragged } if (this._lockFrozen && host.isPinnedColumn(colIndex)) { return; // If the lock frag is on, frozen columns cannot be dragged } - var rowIndex = this._pos["rowIndex"]; // rowIndex may not exist - var movableBorder = this._findMoveableBorder(colIndex, rowIndex - 1, section); - var movingColumns = this._getSpan(colIndex, rowIndex, section); + let rowIndex = this._pos["rowIndex"]; // rowIndex may not exist + let movableBorder = this._findMoveableBorder(colIndex, rowIndex - 1, section); + let movingColumns = this._getSpan(colIndex, rowIndex, section); this._clickedGrid = host; this._clickedSection = section; this._clickedRow = rowIndex; @@ -37771,11 +37773,11 @@ Recommended fix: window.addEventListener("mousemove", this._onDrag, false); // TODO: support touch operation window.addEventListener("mouseup", this._onDragEnd, true); - var host = this._clickedGrid; - var height = host.getHeight(); - var sectionBound = this._clickedSection.getBoundingClientRect(); - var clickedCellBound = this._clickedSection.getCell(this._startColumn, this._clickedRow).getBoundingClientRect(); - var gridElem = host.getElement(); + let host = this._clickedGrid; + let height = host.getHeight(); + let sectionBound = this._clickedSection.getBoundingClientRect(); + let clickedCellBound = this._clickedSection.getCell(this._startColumn, this._clickedRow).getBoundingClientRect(); + let gridElem = host.getElement(); this._guideline.style.top = clickedCellBound.top - sectionBound.top + "px"; this._guideline.style.height = height - 1 + "px"; @@ -37786,10 +37788,10 @@ Recommended fix: gridElem.appendChild(this._guideline); if (this._dragBoxRenderer) { // For custom drag box rendering - var arg = cloneObject(e); // TODO: Check if cloning is necessary - var id = this.getColumnId(this._startColumn); - var index = this.getColumnIndex(id); - var field = this._getField(this._startColumn); + let arg = cloneObject(e); // TODO: Check if cloning is necessary + let id = this.getColumnId(this._startColumn); + let index = this.getColumnIndex(id); + let field = this._getField(this._startColumn); arg.dragBox = this._dragBox; arg.columnData = { index: index, @@ -37812,7 +37814,7 @@ Recommended fix: } else if (this._scrollStep > 400) { this._scrollStep = 400; } - var scrollbar = host.getHScrollbar(); + let scrollbar = host.getHScrollbar(); this._cacheLeft = scrollbar.getLeft() + 20; this._cacheWidth = scrollbar.getLeft() + scrollbar.getWidth() - 20; this._dragPulseId = window.setInterval(this._onDragPulse, 150); // Start pulse @@ -37831,7 +37833,7 @@ Recommended fix: if (!host || host !== this._clickedGrid) { return; } - var colIndex = this._pos["colIndex"]; + let colIndex = this._pos["colIndex"]; if (colIndex >= this._leftMovableBorder && colIndex <= this._rightMovableBorder && this._isAllowed(colIndex) && !(this._lockFrozen && host.isPinnedColumn(colIndex))) { e.dragBox = this._dragBox; this._renderGuideline(); @@ -37852,7 +37854,7 @@ Recommended fix: document.body.classList.remove("tr-dragging"); // document.body.classList.remove("tr-move-cursor"); this._dimCol(false); - var pn = this._guideline.parentNode; + let pn = this._guideline.parentNode; if (pn) { pn.removeChild(this._guideline); } @@ -37868,10 +37870,10 @@ Recommended fix: window.clearInterval(this._dragPulseId); this._dragPulseId = 0; } - var destPos = this._pos; + let destPos = this._pos; this._pos = null; preventDefault(e); - var operationCancelled = false; + let operationCancelled = false; if (destPos["cancel"]) { operationCancelled = true; } @@ -37888,7 +37890,7 @@ Recommended fix: this._destColumn < 0 || !this._isAllowed(this._destColumn) || this._destColumn >= this._startColumn && this._destColumn <= this._endColumn) { operationCancelled = true; } - var arg = null; + let arg = null; if (!operationCancelled) { arg = { "startColumnIndex": this._startColumn, @@ -37940,13 +37942,14 @@ Recommended fix: let colList = []; let csp = this._getPlugin("ColumnStackPlugin"); let stackId, groupId; + let i; if (srcCount === 1) { if (csp) { stackId = csp.getStackId(this._startColumn); } let cgp = this._getPlugin("ColumnGroupingPlugin"); if (cgp) { - var cellInfo = cgp.getCellInfo(this._startPos); + let cellInfo = cgp.getCellInfo(this._startPos); groupId = cellInfo["groupId"] || cellInfo["columnId"]; } if (stackId && this._startColumn === this._endColumn) { @@ -37954,15 +37957,14 @@ Recommended fix: } else if (groupId) { cgp.moveGroup(groupId, destColumnIndex); } else { - for (let i = this._startColumn; i <= this._endColumn; i++) { + for (i = this._startColumn; i <= this._endColumn; i++) { colList.push(i); } } } else { let stacking = {}; // Object to optimize call column stack api repeatly - for (let i = 0; i < srcCount; i++) { + for (i = 0; i < srcCount; i++) { let srcIdx = srcColIndices[i]; - let srcId = this.getColumnId(srcIdx); if (csp) { stackId = csp.getStackId(srcIdx); } @@ -37974,12 +37976,13 @@ Recommended fix: colList.push(colId); } } else { + let srcId = this.getColumnId(srcIdx); colList.push(srcId); // Normal case } } } - for (let i = this._hosts.length; --i >= 0;) { - var host = this._hosts[i]; + for (i = this._hosts.length; --i >= 0;) { + let host = this._hosts[i]; host.reorderColumns(colList, destColumnIndex); } }; @@ -37991,19 +37994,19 @@ Recommended fix: return; } this._dispatch("dragInterval", this._pos); - var host = this._clickedGrid; + let host = this._clickedGrid; if (!host || !host.getHScrollbar().isActive()) { return; } - var x = this._pos["x"]; - var scrollVal = 0; + let x = this._pos["x"]; + let scrollVal = 0; if (x < this._cacheLeft) { scrollVal = -Math.floor(this._scrollStep * (0.8 + Math.random())); } else if (x > this._cacheWidth) { scrollVal = Math.floor(this._scrollStep * (0.8 + Math.random())); } - var len = this._hosts ? this._hosts.length : 0; - for (var i = 0; i < len; ++i) { + let len = this._hosts ? this._hosts.length : 0; + for (let i = 0; i < len; ++i) { this._hosts[i].scrollRight(scrollVal); } }; @@ -38025,7 +38028,7 @@ Recommended fix: * @return {!Object} */ ColumnDraggingPlugin.prototype._getSpan = function (colIndex, row, section) { - var cellSpan = section.getCellColSpan(colIndex, row); + let cellSpan = section.getCellColSpan(colIndex, row); if (cellSpan <= 0) { // The specified cell is being occupied colIndex += cellSpan; // Convert the given negative index to the spanning cell @@ -38050,7 +38053,7 @@ Recommended fix: "right": section.getColumnCount() - 1 }; } - var span = this._getSpan(col, row, section); + let span = this._getSpan(col, row, section); if (span["right"] >= span["left"]) { return span; } else { @@ -38061,27 +38064,27 @@ Recommended fix: * @private */ ColumnDraggingPlugin.prototype._renderGuideline = function () { - var colIndex = this._pos["colIndex"]; + let colIndex = this._pos["colIndex"]; if (colIndex == null || colIndex < 0) { // undefined, null or negative number return; } - var currentSpan = this._getSpan(colIndex, this._clickedRow, this._clickedSection); - var colStart = currentSpan["left"]; // This can be different from colIndex - var colEnd = currentSpan["right"]; - var colLeft = this._clickedGrid.getColumnLeft(colStart); - var colWidth = 0; - for (var i = colStart; i <= colEnd; ++i) { + let currentSpan = this._getSpan(colIndex, this._clickedRow, this._clickedSection); + let colStart = currentSpan["left"]; // This can be different from colIndex + let colEnd = currentSpan["right"]; + let colLeft = this._clickedGrid.getColumnLeft(colStart); + let colWidth = 0; + for (let i = colStart; i <= colEnd; ++i) { colWidth += this._clickedGrid.getColumnWidth(i); } - var rightHand = this._pos["x"] > colLeft + colWidth / 2; - var destColumn = rightHand ? colEnd + 1 : colStart; - var csp = this._getPlugin("ColumnStackPlugin"); + let rightHand = this._pos["x"] > colLeft + colWidth / 2; + let destColumn = rightHand ? colEnd + 1 : colStart; + let csp = this._getPlugin("ColumnStackPlugin"); if (csp) { - var stackId = csp.getStackId(destColumn); + let stackId = csp.getStackId(destColumn); if (stackId) { - var members = csp.getStackMemberIndices(stackId); - var memberCount = members.length; + let members = csp.getStackMemberIndices(stackId); + let memberCount = members.length; if (members && memberCount) { destColumn = rightHand ? members[memberCount - 1] + 1 : members[0]; } @@ -38106,9 +38109,9 @@ Recommended fix: * @param {boolean} inOut */ ColumnDraggingPlugin.prototype._dimCol = function (inOut) { - var host = this._clickedGrid; - var titleCell = host.getSection("title").getColumn(this._startColumn).getCell(this._clickedRow); - var titleCellEl = titleCell.getElement(); + let host = this._clickedGrid; + let titleCell = host.getSection("title").getColumn(this._startColumn).getCell(this._clickedRow); + let titleCellEl = titleCell.getElement(); if (inOut) { titleCellEl.classList.add("drag-indicator"); } else { @@ -66451,7 +66454,6 @@ Recommended fix: t._onDragStart = t._onDragStart.bind(t); t._onMouseMove = t._onMouseMove.bind(t); t._onDragEnd = t._onDragEnd.bind(t); - t._onThemeLoaded = t._onThemeLoaded.bind(t); t._onJETDrop = t._onJETDrop.bind(t); t._onJETDragOver = t._onJETDragOver.bind(t); t._delayStart = t._delayStart.bind(t); @@ -66606,15 +66608,6 @@ Recommended fix: */ RowDraggingPlugin.prototype._entryPoint = ""; - /** Applied theme color in row dragging and dragUI - * @private - * @param {Object} host core grid instance - */ - let _applyStyles = function (host) { - RowDraggingPlugin._applyThemeColor(host); - DragUI.applyThemeColor(host); - }; - /** Prevent built-in config * @public * @ignore @@ -66665,14 +66658,7 @@ Recommended fix: dragBox: this._dragBox, dragBoxIcon: this._dragBoxIcon }); - - // Share dragging styles - if (!DragUI.stylePromise) { - DragUI.stylePromise = ElfUtil.getThemeColors(); - DragUI.stylePromise.then(this._onThemeLoaded).catch(this._onThemeLoaded); - } - // TODO: Create a manager to manage styles. Currently, we have to use setTimeout to wait for an element to be created before applying styles - setTimeout(_applyStyles.bind(this, host), 0); + ElfUtil.getThemeColors().then(RowDraggingPlugin._onThemeLoaded.bind(null, host)).catch(RowDraggingPlugin._onThemeLoaded.bind(null, host)); // In case of lazy loading // host.getAllSections("content").forEach(this._registerSection); @@ -66707,17 +66693,17 @@ Recommended fix: }; /** @private + * @function + * @param {Object} grid Core grid instance */ - RowDraggingPlugin.prototype._onThemeLoaded = function () { + RowDraggingPlugin._onThemeLoaded = function (grid) { if (!RowDraggingPlugin._styles) { let styles = [":host .row-dragging .cover-layer .selection-bound", ["border: var(--grid-drag-indicator)"], ":host .row-dragging .tr-lg .cell.selected-row", ["background-color: unset;"]]; RowDraggingPlugin._styles = prettifyCss(styles); } - let colors = ElfUtil.getColors(); - this._dragUI.onThemeLoaded(colors); // TODO : onThemeLoaded should be static function like DragUI.applyThemeColor - for (let i = this._hosts.length; --i >= 0;) { - _applyStyles(this._hosts[i]); - } + DragUI.initStyles(); + RowDraggingPlugin._applyThemeColor(grid); + DragUI.applyThemeColor(grid); }; /** @private * @param {Object} grid core grid instance @@ -172260,7 +172246,7 @@ Recommended fix: ; // CONCATENATED MODULE: ./public/lib/grid/index.js window.EFX_GRID = { - version: "6.0.149" + version: "6.0.150" }; ; // CONCATENATED MODULE: ./public/lib/grid/themes/halo/light/efx-grid.js @@ -180165,7 +180151,7 @@ Recommended fix: dispatchEvent(new CustomEvent('ef.nativeStyles.define', { detail: { name: 'html', - styles: 'html{height:100%;touch-action:manipulation;-webkit-tap-highlight-color:transparent;scrollbar-face-color:#999;scrollbar-shadow-color:#999;scrollbar-highlight-color:#999;scrollbar-arrow-color:#999;scrollbar-track-color:#f2f2f2;scrollbar-3dlight-color:#f2f2f2;scrollbar-darkshadow-color:#f2f2f2;--color-scheme-primary:#334BFF;--color-scheme-secondary:#6678FF;--color-scheme-tertiary:#FAFAFA;--color-scheme-complementary:#0D0D0D;--color-scheme-negative:#B63243;--color-scheme-neutral:#404040;--color-scheme-positive:#246B3E;--color-scheme-tickup:#246B3E;--color-scheme-tickdown:#B63243;--color-scheme-ticktext:#FFFFFF;--theme-name:\'halo-theme\';--theme-version:\'6.8.1\'}html[movement-color-profile=asian1]{--color-scheme-negative:#246B3E;--color-scheme-neutral:#404040;--color-scheme-positive:#B63243;--color-scheme-tickup:#B63243;--color-scheme-tickdown:#246B3E}html[movement-color-profile=asian2],html[movement-color-profile=european]{--color-scheme-negative:#B63243;--color-scheme-neutral:#246B3E;--color-scheme-positive:#334BFF;--color-scheme-tickup:#246B3E;--color-scheme-tickdown:#B63243}::-moz-selection{color:#fff;background:#334bff}::selection{color:#fff;background:#334bff}::-webkit-scrollbar-corner{background:0 0}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:#999;border-radius:0;border:1px solid transparent}::-webkit-scrollbar-thumb:hover{background:#1429bd}::-webkit-scrollbar-thumb:active{background:#0f1e8a}::-webkit-scrollbar-track{background:#f2f2f2}::-webkit-scrollbar-thumb:horizontal{background-size:auto 6px;background-repeat:repeat-x;background-image:linear-gradient(to bottom,#999,#999);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:horizontal:hover{background-image:linear-gradient(to bottom,#1429bd,#1429bd);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:horizontal:active{background-image:linear-gradient(to bottom,#0f1e8a,#0f1e8a);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical{background-size:6px auto;background-repeat:repeat-y;background-image:linear-gradient(to right,#999,#999);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical:hover{background-image:linear-gradient(to right,#1429bd,#1429bd);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical:active{background-image:linear-gradient(to right,#0f1e8a,#0f1e8a);background-color:transparent;background-position:center}::-webkit-scrollbar-track:horizontal{border-top:1px solid #fff;border-bottom:1px solid #fff}::-webkit-scrollbar-track:vertical{border-left:1px solid #fff;border-right:1px solid #fff}::-webkit-scrollbar-button{background:0 0/1px 2px no-repeat #f2f2f2;height:16px;width:16px;display:none;border:1px solid #fff}::-webkit-scrollbar-button:end:decrement,::-webkit-scrollbar-button:start:increment{display:none}::-webkit-scrollbar-button:hover{background-color:#1429bd;border:1px solid #1429bd}::-webkit-scrollbar-button:active{background-color:#0f1e8a;border:1px solid #fff}::-webkit-scrollbar-button:horizontal{background-size:2px 1px}::-webkit-scrollbar-button:vertical:start:decrement{border-bottom-color:#fff;background-image:linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px}::-webkit-scrollbar-button:vertical:start:decrement:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px;border-bottom-color:#1429bd}::-webkit-scrollbar-button:vertical:start:decrement:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px;border-bottom-color:#fff}::-webkit-scrollbar-button:vertical:end:increment{border-top-color:#fff;background-image:linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px}::-webkit-scrollbar-button:vertical:end:increment:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px;border-top-color:#1429bd}::-webkit-scrollbar-button:vertical:end:increment:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px;border-top-color:#fff}::-webkit-scrollbar-button:horizontal:start:decrement{border-right-color:#fff;background-image:linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px}::-webkit-scrollbar-button:horizontal:start:decrement:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px;border-right-color:#1429bd}::-webkit-scrollbar-button:horizontal:start:decrement:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px;border-right-color:#fff}::-webkit-scrollbar-button:horizontal:end:increment{border-left-color:#fff;background-image:linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px}::-webkit-scrollbar-button:horizontal:end:increment:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px;border-left-color:#1429bd}::-webkit-scrollbar-button:horizontal:end:increment:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px;border-left-color:#fff}@supports not selector(::-webkit-scrollbar){html{scrollbar-color:#999 #f2f2f2;scrollbar-width:thin;scrollbar-width:auto}}' + styles: 'html{height:100%;touch-action:manipulation;-webkit-tap-highlight-color:transparent;scrollbar-face-color:#999;scrollbar-shadow-color:#999;scrollbar-highlight-color:#999;scrollbar-arrow-color:#999;scrollbar-track-color:#f2f2f2;scrollbar-3dlight-color:#f2f2f2;scrollbar-darkshadow-color:#f2f2f2;--color-scheme-primary:#334BFF;--color-scheme-secondary:#6678FF;--color-scheme-tertiary:#FAFAFA;--color-scheme-complementary:#0D0D0D;--color-scheme-negative:#B63243;--color-scheme-neutral:#404040;--color-scheme-positive:#246B3E;--color-scheme-tickup:#246B3E;--color-scheme-tickdown:#B63243;--color-scheme-ticktext:#FFFFFF;--theme-name:\'halo-theme\';--theme-version:\'6.9.0\'}html[movement-color-profile=asian1]{--color-scheme-negative:#246B3E;--color-scheme-neutral:#404040;--color-scheme-positive:#B63243;--color-scheme-tickup:#B63243;--color-scheme-tickdown:#246B3E}html[movement-color-profile=asian2],html[movement-color-profile=european]{--color-scheme-negative:#B63243;--color-scheme-neutral:#246B3E;--color-scheme-positive:#334BFF;--color-scheme-tickup:#246B3E;--color-scheme-tickdown:#B63243}::-moz-selection{color:#fff;background:#334bff}::selection{color:#fff;background:#334bff}::-webkit-scrollbar-corner{background:0 0}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-thumb{background:#999;border-radius:0;border:1px solid transparent}::-webkit-scrollbar-thumb:hover{background:#1429bd}::-webkit-scrollbar-thumb:active{background:#0f1e8a}::-webkit-scrollbar-track{background:#f2f2f2}::-webkit-scrollbar-thumb:horizontal{background-size:auto 6px;background-repeat:repeat-x;background-image:linear-gradient(to bottom,#999,#999);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:horizontal:hover{background-image:linear-gradient(to bottom,#1429bd,#1429bd);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:horizontal:active{background-image:linear-gradient(to bottom,#0f1e8a,#0f1e8a);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical{background-size:6px auto;background-repeat:repeat-y;background-image:linear-gradient(to right,#999,#999);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical:hover{background-image:linear-gradient(to right,#1429bd,#1429bd);background-color:transparent;background-position:center}::-webkit-scrollbar-thumb:vertical:active{background-image:linear-gradient(to right,#0f1e8a,#0f1e8a);background-color:transparent;background-position:center}::-webkit-scrollbar-track:horizontal{border-top:1px solid #fff;border-bottom:1px solid #fff}::-webkit-scrollbar-track:vertical{border-left:1px solid #fff;border-right:1px solid #fff}::-webkit-scrollbar-button{background:0 0/1px 2px no-repeat #f2f2f2;height:16px;width:16px;display:none;border:1px solid #fff}::-webkit-scrollbar-button:end:decrement,::-webkit-scrollbar-button:start:increment{display:none}::-webkit-scrollbar-button:hover{background-color:#1429bd;border:1px solid #1429bd}::-webkit-scrollbar-button:active{background-color:#0f1e8a;border:1px solid #fff}::-webkit-scrollbar-button:horizontal{background-size:2px 1px}::-webkit-scrollbar-button:vertical:start:decrement{border-bottom-color:#fff;background-image:linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px}::-webkit-scrollbar-button:vertical:start:decrement:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px;border-bottom-color:#1429bd}::-webkit-scrollbar-button:vertical:start:decrement:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 8px,9.55px 7px,8.55px 6px,7.55px 5px,6.55px 4px,5.55px 5px,4.55px 6px,3.55px 7px,2.55px 8px;border-bottom-color:#fff}::-webkit-scrollbar-button:vertical:end:increment{border-top-color:#fff;background-image:linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px}::-webkit-scrollbar-button:vertical:end:increment:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px;border-top-color:#1429bd}::-webkit-scrollbar-button:vertical:end:increment:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:10.55px 4px,9.55px 5px,8.55px 6px,7.55px 7px,6.55px 8px,5.55px 7px,4.55px 6px,3.55px 5px,2.55px 4px;border-top-color:#fff}::-webkit-scrollbar-button:horizontal:start:decrement{border-right-color:#fff;background-image:linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px}::-webkit-scrollbar-button:horizontal:start:decrement:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px;border-right-color:#1429bd}::-webkit-scrollbar-button:horizontal:start:decrement:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:7.5px 10.55px,6.5px 9.55px,5.5px 8.55px,4.5px 7.55px,3.5px 6.55px,4.5px 5.55px,5.5px 4.55px,6.5px 3.55px,7.5px 2.55px;border-right-color:#fff}::-webkit-scrollbar-button:horizontal:end:increment{border-left-color:#fff;background-image:linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959),linear-gradient(#595959,#595959);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px}::-webkit-scrollbar-button:horizontal:end:increment:hover{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px;border-left-color:#1429bd}::-webkit-scrollbar-button:horizontal:end:increment:active{background-image:linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff),linear-gradient(#fff,#fff);background-position:5px 10.55px,6px 9.55px,7px 8.55px,8px 7.55px,9px 6.55px,8px 5.55px,7px 4.55px,6px 3.55px,5px 2.55px;border-left-color:#fff}@supports not selector(::-webkit-scrollbar){html{scrollbar-color:#999 #f2f2f2;scrollbar-width:thin;scrollbar-width:auto}}' } })); ; // CONCATENATED MODULE: ./node_modules/@refinitiv-ui/halo-theme/light/input.js diff --git a/template-100.html b/template-100.html index 75b98902..8556fbd6 100644 --- a/template-100.html +++ b/template-100.html @@ -1,29 +1,238 @@ -

Changing Formatter at Runtime

-

Sometimes you might want to change a custom rendering at runtime. This can be achieved by using setColumnFormatter method.

-
-

APIs for Grid and the setColumnFormatter() method description can be found here.

-
-
var grid = document.getElementsByTagName("efx-grid")[0];
-
-// formatter can be a function
-var formatter = function(e) {
-    var value = e.grid.getRowData(e.rowIndex)[e.field];
-    e.cell.setContent(value);
-};
+

Text Selection

+

Text selection has 2 scopes. It's grid scope and column scope. The default value of text selection is disabled, but you can enable it. If you enable it, users can select text in scope.

+ +

Limitation with safari

+ +

Example

+

If you use Safari, try clicking the button in column Market from the sample below. You won't be able to receive the click event.

+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
 
-/*
-// or can be an object.
-var formatter = {
-    binding: function(e) {
-        var value = e.grid.getRowData(e.rowIndex)[e.field];
-        e.cell.setContent(value);
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market"];
+var records = DataGenerator.generateRecords(fields, { numRows: 10 });
+var buttonDisplay = {
+binding: function (e) {
+    var cellData = e.cell;
+    var buttonContent = document.createElement("button");
+    var spanContent = document.createElement("span");
+    buttonContent.addEventListener("click" , () => {
+        alert(e.data);
+    });
+    spanContent.textContent = `${e.data}`;
+    buttonContent.appendChild(spanContent);
+    cellData.setContent(buttonContent);
     }
 };
-// or can be a predefined formatter
-var formatter = SimpleLinkFormatter.create()
-*/
 
-function handleChangeFormatter() {
-    grid.api.setColumnFormatter(0 /* Column Index */, formatter);
+var configObj = {
+    rowVirtualRendering: false,
+    textSelect : true,
+    columns: [
+        {name: "Company", field: fields[0]},
+        {name: "Market", field: fields[1], formatter: buttonDisplay , width: 120}
+    ],
+    staticDataRows: records
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+

Limitation with row virtualization

+

Text selection with row virtualization cannot select all data in the grid. +In the example below, the grid has text selection enabled and uses row virtualization. +When you try to select and copy text from the grid and paste it into a text area, you will see that not all data from the grid is obtained. +This is because row virtualization render only the rows that is visible in the grid's viewport. +For example, if you have 50 rows of data, but the grid can only show the first 10 rows at a time, then when you try to select the text, it will only select the first 14 rows (10 rows + buffer rows). +If you want to know about row virtualization in more detail, you can refer to the Understanding row virtualization section in the Custom Formatter page.

+

Example

+
efx-grid {
+    height: 300px;
+}
+textarea {
+    height: 200px;
+    width: 100%;
+}
+
+
<efx-grid id="grid"></efx-grid>
+<hr>
+<textarea placeholder="Paste text here"></textarea>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = [
+    "id",
+    "companyName",
+    "market",
+    "CF_LAST",
+    "CF_NETCHNG",
+    "industry"
+];
+var records = DataGenerator.generateRecords(fields, { numRows: 50, seed: 0 });
+var config = {
+    textSelect: true,
+    columns: [
+        {
+            field: fields[0],
+            name: "ID"
+        },
+        {
+            field: fields[1],
+            name: "Company Name"
+        },
+        {
+            field: fields[2],
+            name: "Market"
+        },
+        {
+            field: fields[3],
+            name: "Last"
+        },
+        {
+            field: fields[4],
+            name: "Net. Chng"
+        },
+        {
+            field: fields[5],
+            name: "Industry"
+        },
+    ],
+    staticDataRows: records
+};
+
+var grid = document.getElementById("grid");
+grid.config = config;
+window.grid = grid;
+
+

Copying all content in the grid without text selection

+

If you want to copy all the data in the grid, you can do it by focusing on the grid element and modifying the clipboard without text selection. +To do this, you can listen for the click event on the grid element and call focus method on the grid API to focus on the grid. +Then, you can listen for the copy event on the grid element and modify the clipboard as shown in the example below.

+

Example

+
html body {
+    padding: 5px;
+    box-sizing: border-box;
+}
+html hr {
+    margin: 5px;
+}
+efx-grid {
+    height: 200px;
+}
+efx-grid:focus-within {
+    outline-width: 1px;
+    outline-style: solid;
+    outline-color: blue;
+}
+textarea {
+    width: 100%;
+    height: 200px;
 }
+mark {
+    opacity: 0;
+    padding: 4px;
+    transition: opacity 0.5s ease-out;
+}
+
+
<big>Try clicking grid and copying (<b>Ctrl/Command + C</b>) grid's content.</big>
+<br>
+<big>Then, paste the content on the text box below.</big>
+<hr>
+<mark id="key_indi"></mark>
+<hr>
+<efx-grid id="grid"></efx-grid>
+<hr>
+<textarea placeholder="Paste clipboard content here"></textarea>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+
+var fields = ["id", "companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 });
+
+function onClick(e) {
+    grid.api.focus();
+}
+function onCopy(e) {
+    var columnNames = grid.api.getColumnNames();
+    var rows = grid.api.getMultipleRowData(); // Get all row data from existing view
+    
+    // Build text in TSV format 
+    var text = columnNames.join("\t") + "\n" +
+        rows.map(recordToTSV).join("\n");
+    
+    e.clipboardData.setData("text/plain", text);
+    e.preventDefault();
+    
+    showKeyIndicator("Data is copied to clipboard");
+}
+function recordToTSV(record) {
+    return ([
+        record[fields[0]],
+        record[fields[1]],
+        record[fields[2]],
+        record[fields[3]],
+        record[fields[4]]
+    ]).join("\t"); // TSV (Tab Separated Values)
+}
+function showKeyIndicator(text) {
+    if(text) {
+        key_indi.textContent = text;
+    }
+    key_indi.style.opacity = "1";
+    setTimeout(onHideKeyIndicator, 1000);
+}
+function onHideKeyIndicator() {
+    key_indi.style.opacity = "";
+}
+
+var configObj = {
+    sorting: {
+        sortableColumns: true
+    },
+    columns: [
+        { name: "Id", field: fields[0], width: 40 },
+        { name: "Company", field: fields[1] },
+        { name: "Market", field: fields[2], width: 100 },
+        { name: "Last", field: fields[3], width: 80 },
+        { name: "Net. Chng", field: fields[4], width: 80 },
+        { name: "Industry", field: fields[5] }
+    ],
+    staticDataRows: records,
+    extensions: []
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+grid.addEventListener("click", onClick);
+grid.addEventListener("copy", onCopy);
 
+



diff --git a/template-101.html b/template-101.html index dbfbd474..75b98902 100644 --- a/template-101.html +++ b/template-101.html @@ -1,52 +1,29 @@ -

Formatter (default)

-

Formatter is what Grid uses to render content. Grid's default formatter will render any data in plain text. When data is updated, Grid will bind the data from its own internal data source to render the data in plain text using the formatter. The data given to grid can be any data type.

+

Changing Formatter at Runtime

+

Sometimes you might want to change a custom rendering at runtime. This can be achieved by using setColumnFormatter method.

-

Note: The formatter will be repeatedly executed multiple times for every update and scrolling.

+

APIs for Grid and the setColumnFormatter() method description can be found here.

-

Default rendering is already optimized for row virtualization. This means that grid uses the same text element to render different data for different rows. It should be fast enough to handle rendering a million of rows.

-

To update what is shown on the Grid, please use Grid's APIs to manipulate the data from the instance.

-

Example

-
efx-grid {
-    height: 200px;
-}
-
-
<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
var grid = document.getElementsByTagName("efx-grid")[0];
 
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var records = DataGenerator.generateRecords(fields, { numRows: 40 });
-var configObj = {
-    columns: [
-        {name: "Company", field: fields[0]},
-        {name: "Market", field: fields[1]},
-        {name: "Last", field: fields[2]},
-        {name: "Net. Chng", field: fields[3]},
-        {name: "Industry", field: fields[4]}
-    ],
-    staticDataRows: records
+// formatter can be a function
+var formatter = function(e) {
+    var value = e.grid.getRowData(e.rowIndex)[e.field];
+    e.cell.setContent(value);
 };
 
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-

Internal Default Formatter Implementation

-

Internally, Grid implements the formatter as the following code:

-
var configObj = {
-    columns: [
-        { binding: function(e){
-                e.cell.setContent(e.data);
-            }
-        }
-    ]
+/*
+// or can be an object.
+var formatter = {
+    binding: function(e) {
+        var value = e.grid.getRowData(e.rowIndex)[e.field];
+        e.cell.setContent(value);
+    }
 };
+// or can be a predefined formatter
+var formatter = SimpleLinkFormatter.create()
+*/
+
+function handleChangeFormatter() {
+    grid.api.setColumnFormatter(0 /* Column Index */, formatter);
+}
 
-

Custom Formatter

-

If we want anything other than simple text, we need to define a custom formatter. You can find more details about this in the Custom Formatter section.

diff --git a/template-102.html b/template-102.html index 937fcf6e..dbfbd474 100644 --- a/template-102.html +++ b/template-102.html @@ -1,184 +1,12 @@ -

Custom Formatter

-

Since Grid utilizes a row virtualization technique, where the same cell is reused across different rows, you cannot simply just create any content and stop there. With row virtualization the custom content that you are trying to create or render will be reused in the different rows. So you have to create the content once and reuse it from the cache. Then, you need to bind data from Grid's data store to the content for each data update and scrolling.

-

The process for writing the formatter is usually something like the following code:

-
var formatter = function(e) {
-    var cell = e.cell;
-    // Cache checking part (Reuse the same element)
-    var element = cell.getContent();
-    if (!element) {
-        // Element creation part
-        element = document.createElement('tag-name');
-
-        // Apply common static settings (once per element creation) here
-        // This could be attributes, styles, event listeners, and etc.
-        element.style.color = "red";
-    }
-
-    // Element updating part (bind data to the UI element)
-    element.value = e.data; // IMPORTANT
-
-    // The below code is required. It does not post any significant performance impact
-    cell.setContent(element);
-};
-
-

Defining the formatter

-

The formatter can be specified as a function on the binding property of the column configuration object.

-
var configObj = {
-    ...
-    columns: [
-        {
-            field: "Field 1", 
-            binding: function(e) {
-                e.cell.setContent(e.data);
-            }
-        },
-        ...
-    ],
-    ...
-}
-
-
-

For displaying simple text you do not need to create a custom formatter, as Grid already has simple text as its default formatter.

-
-

Common form and structure

-

binding method will be called multiple times during user scrolling. The key here is to create a DOM element only once, reuse the same element and update the data every time the method is called.

-

In general, the steps are as the following steps:

-
    -
  1. Check if the content already exists
  2. -
  3. If it exists, skip to the next step. If the content does not exist, create the content
  4. -
  5. Update the data to the content
  6. -
  7. Set the content to the cell
  8. -
-

Below is the most common form of formatter. It is recommended to write most custom formatters in this form and structure.

-
var formatter = function(e){
-    var cell = e.cell;
-    var content = cell.getContent(); // Utilize cache
-    if (!content) { // Check if cache exists
-        content = document.createElement("xxx-xxxx");
-        // Initialize element once
-        var subContent = document.createElement("yyyy");
-        subContent.style.color = "brown"; 
-        
-        var subContent2 = document.createElement("zz-zzz");
-        content._myContent = subContent2;
-        
-        content.appendChild(subContent);
-        content.appendChild(subContent2);
-    }
-    
-    content._myContent.textContent = e.data; // IMPORTANT
-    
-    cell.setContent(content); // Always set the content to allow multiple types of content in the same column
-};
-
-

Setting styles in the formatter

-

When making any type of modification in the binding method, you must reset the value back because the same cell will be reused by different rows.

-
var formatter = function(e){
-    var cell = e.cell;
-    var data = e.data;
-    var content = cell.getContent();
-    if (!content) {
-        content = document.createElement("span");
-        content.style.color = "salmon"; // Static styling
-    }
-    
-    // Dynamic styling
-    if(data > 0) {
-        content.style.backgroundColor = "green";
-    } else if(data < 0) {
-        content.style.backgroundColor = "red";
-    } else {
-        content.style.backgroundColor = ""; // Reset the background
-    }
-    cell.setStyle("fontSize", Math.abs(data) > 10 ? "1.5em" : ""); // Styles can be applied to either the cell content or the cell itself.
-    
-    content.textContent = data;
-    cell.setContent(content);
-};
-
-

Interactive content

-

States must be saved back to Grid after users make changes to the content. This is because Grid's row virtualization will reuse the same content during the scroll. Also note that user interaction does not happen during the data binding. User interaction is an asynchronous operation. So do not rely on closure variables or inline functions.

-

Contexts and values may be a different. You will need to resolve the position or context at runtime by using [getRelativePosition(./rendering/).

-
var formatter = function(e){
-    var cell = e.cell;
-    var dropdown = cell.getContent();
-    if (!dropdown) {
-        dropdown = document.createElement("select");
-        dropdown.addEventListener("change", dropdownChangeHandler); // Handle user interaction
-        
-        for(var i = 0; i < 3; ++i) {
-            var option = document.createElement("option");
-            option.value = i;
-            option.textContent = "Value " + i;
-            dropdown.appendChild(option);
-        }
-    }
-    
-    dropdown.selectedIndex = e.data;
-    cell.setContent(dropdown);
-};
-var dropdownChangeHandler = function(e) {
-    var dropdown = e.currentTarget;
-    var selectedIndex = dropdown.selectedIndex;
-    
-    var pos = grid.api.getRelativePosition(e);
-    var rowDef = grid.api.getRowDefinition(pos.rowIndex);
-    
-    rowDef.setData("Field XXXX", selectedIndex); // It is important to set the new data
-};
-
-
-

Find out more information about event handling here.

-
-

Content with multiple states

-

Content with multiple states (for example, colors, disabled and invalid states) must have all states stored in the Grid. You can have as many columns' data or fields as we want in order to represent the content.

-

The example below shows input with multiple states depending on the data on other fields.

-
var formatter = function(e){
-    var cell = e.cell;
-    var rowData = e.rowData;
-    var inputElem = cell.getContent();
-    if (!inputElem) {
-        inputElem = document.createElement("input");
-    }
-    
-    var state1 = rowData["someField"];
-    if(state1) {
-        inputElem.setAttribute("disabled", "");
-    } else {
-        inputElem.removeAttribute("disabled");
-    }
-    
-    var state2 = rowData["anotherField"];
-    if(state2) {
-        inputElem.setAttribute("error", "");
-    } else {
-        inputElem.removeAttribute("error");
-    }
-    
-    inputElem.value = e.data;
-    cell.setContent(inputElem);
-};
-
+

Formatter (default)

+

Formatter is what Grid uses to render content. Grid's default formatter will render any data in plain text. When data is updated, Grid will bind the data from its own internal data source to render the data in plain text using the formatter. The data given to grid can be any data type.

-

Note: data is completely independent from column UIs. This means you do not have to create a column for data to exist. Data can be added or removed separately from Grid's columns.

+

Note: The formatter will be repeatedly executed multiple times for every update and scrolling.

-

Formatter/binding method parameters

-

Event argument binding method has the following parameter list:

-
    -
  • data : The data value corresponding to the field and row of the cell
  • -
  • cell : The cell object that provides access to the DOM element of the cell
  • -
  • rowIndex : Index of the current row of the cell being rendered
  • -
  • rowDef : The row definition object
  • -
  • rowData : The data object that stores data of the entire row
  • -
  • colIndex : Index of the current column of the cell being rendered
  • -
  • secton : The section object hosting the current column
  • -
-

Understanding row virtualization

-

The row virtualization technique is different from the lazy initialization technique, which creates more content as users scroll down through all the available rows. For example, suppose you have 10,000 rows and Grid's view port can show 20 rows. With row virtualization Grid will create content for around 24 rows (20 rows + buffer rows) throughout Grid's life cycle. With lazy initialization Grid will create content for 24 rows at first load. As users scroll down through the available rows, more and more content will be created. Eventually, all content will be created for all 10,000 rows when using the lazy initialization technique.

-

A web page will get slower as more content/elements are put into the DOM tree. So it's better to reuse the same element whenever possible.

-

Examples

-

Click the green button on the bottom right corner of the live example to see the code.

-
efx-grid {
+

Default rendering is already optimized for row virtualization. This means that grid uses the same text element to render different data for different rows. It should be fast enough to handle rendering a million of rows.

+

To update what is shown on the Grid, please use Grid's APIs to manipulate the data from the instance.

+

Example

+
efx-grid {
     height: 200px;
 }
 
@@ -193,48 +21,15 @@

Examples

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var rangeBarFormatter = function(e) { - var cell = e.cell; - var bar = cell.getContent(); // Utilize caching - if(!bar) { - bar = document.createElement("div"); - bar.style.height = "8px"; - bar.style.position = "relative"; - bar.style.backgroundColor = "#EA7D22"; - - var indi = bar.indi = document.createElement("div"); - indi.style.position = "absolute"; - indi.style.top = "0"; - indi.style.left = "10px"; - indi.style.width = "3px"; - indi.style.height = "100%"; - indi.style.backgroundColor = "white"; - bar.appendChild(indi); - } - cell.setContent(bar); - bar.indi.style.left = (e.data * 100)+"%"; -}; - -var capitalizer = function(e) { - e.cell.setContent(e.data.toString().toUpperCase()); -}; - -var yearDisplay = function(e) { - var cell = e.cell; - cell.setStyle("color", "black"); - cell.setStyle("background-color", "#EA7D22"); - cell.setContent("Year " + e.data.getFullYear()); -}; - -var fields = ["companyName", "market", "CF_LAST", "float_1", "ISODate"]; +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { numRows: 40 }); var configObj = { columns: [ - {name: "Company", field: fields[0], binding: capitalizer}, - {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80}, - {name: "Buy/Sell", field: fields[3], width: 100, binding: rangeBarFormatter}, - {name: "IPO", field: fields[4], alienment: "center", binding: yearDisplay} + {name: "Company", field: fields[0]}, + {name: "Market", field: fields[1]}, + {name: "Last", field: fields[2]}, + {name: "Net. Chng", field: fields[3]}, + {name: "Industry", field: fields[4]} ], staticDataRows: records }; @@ -242,130 +37,16 @@

Examples

var grid = document.getElementById("grid"); grid.config = configObj;
-

Formatting custom content with Text Formatting Extension

-

When using Text Formatting Extension, by default, custom content will be overwritten due to the need for rendering a formatted text by the extension. To format the text inside the custom content and avoid the overriding, you will need to instruct the extension on how and where to do the formatting. See this page for more information.

-

Writing a good formatter

-

Be mindful that the binding method will be executed repeatedly and multiple times during data updates and scrolling. Performance is crucial, so you should write the code with caution. See the following guidelines for writing a good formatter.

-

Use predefined formatters

-

The most common formatters are already prewritten for you. Predefined formatters are optimized and easy to use. See this page for more details.

-

Avoid using innerHTML and innerText

-

innerHTML and innerText from native elements involve text parsing and element creation, both of which are computationally expensive. You can improve performance by avoiding using them.

-
function binding1(e) {
-    var content = document.createElement("div"); // Unneccessary creation as it will be called and created multiple times
-    content.innerHTML = "<span>" + e.data + "</span><span>2</span>"; // Slow due to text parsing and element creations
-    
-    e.cell.setContent(content);
-}
-
-// The above function can be re-writen as the following function
-function binding2(e) {
-    var cell = e.cell;
-    var content = cell.getContent();
-    if(!content) {
-        content = document.createElement("div");
-        var span1 = content._span1 = document.createElement("span"); 
-        var span2 = document.createElement("span");
-        span2.textContent = 2;
-        
-        content.appendChild(span1);
-        content.appendChild(span2);
-    }
-    content._span1.textContent = e.data;
-    cell.setContent(content);
-}
-
-

Avoid creating an element for simple text

-

setContent method is already optimized for simple text.

-
function binding1(e) {
-    var content = document.createElement("div"); // Unneccessary creation
-    content.textContent = e.data + " text";
-    
-    e.cell.setContent(content);
-}
-
-// The above function can be re-writen as the following function
-function binding2(e) {
-    e.cell.setContent(e.data + " text");
-}
-
-

Reuse the same content to avoid element creation

-

Bind method will be executed repeatedly and multiple times during data update and scrolling. Minimize element creation by using cache.

-
function binding1(e) {
-    var content = document.createElement("input"); // Slow
-    content.value = e.data;
-    e.cell.setContent(content);
-}
-
-// The above function can be re-writen as the following function
-function binding2(e) {
-    var cell = e.cell;
-    var content = cell.getContent(); // Get previous content
-    if(!content) {
-        content = document.createElement("input");
-    }
-    content.value = e.data;
-    cell.setContent(content);
-}
-
-

Store element in a variable for easy access

-

For complex structure content, it is faster and easier to use a variable for referencing rather than navigating through a DOM tree.

-
function binding1(e) {
-    var cell = e.cell;
-    var content = cell.getContent();
-    if(!content) {
-        content = document.createElement("div");
-        var span1 = document.createElement("span");
-        var span2 = document.createElement("span");
-        
-        content.appendChild(span1);
-        content.appendChild(span2);
-    }
-    cell.setContent(content);
-    var spans = content.getElementsByTagName("span"); // Slow
-    spans[0].textContent = e.data % 5;
-    spans[1].textContent = e.data % 3;
-}
-
-// The above function can be re-writen as the following function
-function binding2(e) {
-    var cell = e.cell;
-    var content = cell.getContent();
-    if(!content) {
-        content = document.createElement("div");
-        var span1 = content._span1 = document.createElement("span");
-        var span2 = content._span2 = document.createElement("span");
-        
-        content.appendChild(span1);
-        content.appendChild(span2);
-    }
-    content._span1.textContent = e.data % 5;
-    content._span2.textContent = e.data % 3;
-    cell.setContent(content);
-}
-
-
-

Note: Cell can contain only one top level node/element (such as, single content). But a content element can have multiple nested elements.

-
-

Use RowDefinition object for asynchronous operation

-

When dealing with asynchronous operations such as server request and response, it is important to use the correct context and data. Row index, cell element, and page can all be changed during the waiting time. Sorting, filtering, grouping, and pagination can also affect row order. So the most reliable way to identify Grid's row is to use RowDefinition object.

-
function binding1(e) {
-    var cell = e.cell;
-    var content = cell.getContent();
-    if(!content) {
-        content = document.createElement("button");
-        content.addEventListener("click", onRequestingData);
-    }
-    cell.setContent(content);
-}
-
-function onRequestingData(e) {
-    var pos = grid.api.getRelativePosition(e);
-    var rowDef = grid.api.getRowDefinition(pos.rowIndex);
-    
-    requestServerData({}, onServerResponse.bind(null, rowDef));
-}
-
-function onServerResponse(rowDef, resp) {
-    // do something
-}
+

Internal Default Formatter Implementation

+

Internally, Grid implements the formatter as the following code:

+
var configObj = {
+    columns: [
+        { binding: function(e){
+                e.cell.setContent(e.data);
+            }
+        }
+    ]
+};
 
+

Custom Formatter

+

If we want anything other than simple text, we need to define a custom formatter. You can find more details about this in the Custom Formatter section.

diff --git a/template-103.html b/template-103.html index 8f06ac17..937fcf6e 100644 --- a/template-103.html +++ b/template-103.html @@ -1,86 +1,188 @@ -

Event handling and event listeners in formatter

-

If your custom formatter contains some input elements or controls, it's important to bind data back to Grid's internal data source when users input new data through the UI from your custom formatter. Remember, the same element will be used on different rows due to the row virtualization mechanic. If the data is changed by user actions, you need to update the change back to Grid's data source, or else the binding mechanism will replace what the user has changed with the data stored from the Grid's internal source.

-

In short, data should be updated after users interact with the UI input. getRelativePosition() method should be used to resolve current positions relative to the grid element.

+

Custom Formatter

+

Since Grid utilizes a row virtualization technique, where the same cell is reused across different rows, you cannot simply just create any content and stop there. With row virtualization the custom content that you are trying to create or render will be reused in the different rows. So you have to create the content once and reuse it from the cache. Then, you need to bind data from Grid's data store to the content for each data update and scrolling.

+

The process for writing the formatter is usually something like the following code:

+
var formatter = function(e) {
+    var cell = e.cell;
+    // Cache checking part (Reuse the same element)
+    var element = cell.getContent();
+    if (!element) {
+        // Element creation part
+        element = document.createElement('tag-name');
+
+        // Apply common static settings (once per element creation) here
+        // This could be attributes, styles, event listeners, and etc.
+        element.style.color = "red";
+    }
+
+    // Element updating part (bind data to the UI element)
+    element.value = e.data; // IMPORTANT
+
+    // The below code is required. It does not post any significant performance impact
+    cell.setContent(element);
+};
+
+

Defining the formatter

+

The formatter can be specified as a function on the binding property of the column configuration object.

+
var configObj = {
+    ...
+    columns: [
+        {
+            field: "Field 1", 
+            binding: function(e) {
+                e.cell.setContent(e.data);
+            }
+        },
+        ...
+    ],
+    ...
+}
+
-

APIs for data manipulation can be found here. APIs for Grid and getRelativePosition() method description can be found here.

+

For displaying simple text you do not need to create a custom formatter, as Grid already has simple text as its default formatter.

-

The 'reverted' problem

-

When we don't set data back, row virtualization will not work properly and content will not be rendered properly. Suppose that we have a dropdown element in one of the grid columns. Any change that is done to the dropdown box will be reverted if we don't update the data.

-

In the live example below, try the following steps to produce the problem:

+

Common form and structure

+

binding method will be called multiple times during user scrolling. The key here is to create a DOM element only once, reuse the same element and update the data every time the method is called.

+

In general, the steps are as the following steps:

    -
  1. Change the selected option from the dropdown box on the first row. Remember the new selected option
  2. -
  3. Scroll down to the bottom of the grid
  4. -
  5. Scroll back up to the top of the grid
  6. +
  7. Check if the content already exists
  8. +
  9. If it exists, skip to the next step. If the content does not exist, create the content
  10. +
  11. Update the data to the content
  12. +
  13. Set the content to the cell
-
efx-grid {
-    height: 200px;
-    margin-bottom: 40px;
-}
+

Below is the most common form of formatter. It is recommended to write most custom formatters in this form and structure.

+
var formatter = function(e){
+    var cell = e.cell;
+    var content = cell.getContent(); // Utilize cache
+    if (!content) { // Check if cache exists
+        content = document.createElement("xxx-xxxx");
+        // Initialize element once
+        var subContent = document.createElement("yyyy");
+        subContent.style.color = "brown"; 
+        
+        var subContent2 = document.createElement("zz-zzz");
+        content._myContent = subContent2;
+        
+        content.appendChild(subContent);
+        content.appendChild(subContent2);
+    }
+    
+    content._myContent.textContent = e.data; // IMPORTANT
+    
+    cell.setContent(content); // Always set the content to allow multiple types of content in the same column
+};
 
-
<efx-grid></efx-grid>
+

Setting styles in the formatter

+

When making any type of modification in the binding method, you must reset the value back because the same cell will be reused by different rows.

+
var formatter = function(e){
+    var cell = e.cell;
+    var data = e.data;
+    var content = cell.getContent();
+    if (!content) {
+        content = document.createElement("span");
+        content.style.color = "salmon"; // Static styling
+    }
+    
+    // Dynamic styling
+    if(data > 0) {
+        content.style.backgroundColor = "green";
+    } else if(data < 0) {
+        content.style.backgroundColor = "red";
+    } else {
+        content.style.backgroundColor = ""; // Reset the background
+    }
+    cell.setStyle("fontSize", Math.abs(data) > 10 ? "1.5em" : ""); // Styles can be applied to either the cell content or the cell itself.
+    
+    content.textContent = data;
+    cell.setContent(content);
+};
 
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["id", "dropdownVal", "boolean", "text"];
-// For static data initialization
-var records = [];
-for (var i = 0; i < 50; i++) {
-    var record = {};
-    record[fields[0]] = i;
-    record[fields[1]] = i % 4; 
-    record[fields[2]] = i & 1 ? true : false;
-    record[fields[3]] = i + " Some Texts";
-    records.push(record);
-}
-
-var dropdownFormatter = function(e) {
+

Interactive content

+

States must be saved back to Grid after users make changes to the content. This is because Grid's row virtualization will reuse the same content during the scroll. Also note that user interaction does not happen during the data binding. User interaction is an asynchronous operation. So do not rely on closure variables or inline functions.

+

Contexts and values may be a different. You will need to resolve the position or context at runtime by using [getRelativePosition(./rendering/).

+
var formatter = function(e){
     var cell = e.cell;
     var dropdown = cell.getContent();
-    if (!dropdown || !dropdown._myDropdown) {
+    if (!dropdown) {
         dropdown = document.createElement("select");
-        dropdown._myDropdown = true;
-        [0, 1, 2, 3].forEach(function(val) {
+        dropdown.addEventListener("change", dropdownChangeHandler); // Handle user interaction
+        
+        for(var i = 0; i < 3; ++i) {
             var option = document.createElement("option");
-            option.value = val;
-            option.textContent = "Value " + val;
+            option.value = i;
+            option.textContent = "Value " + i;
             dropdown.appendChild(option);
-        });
+        }
     }
     
     dropdown.selectedIndex = e.data;
     cell.setContent(dropdown);
 };
-
-var configObj = {
-    columns: [
-        { name: "Row Index", field: fields[0], width: 80 },
-        { name: "Dropdown", field: fields[1], binding: dropdownFormatter },
-        { name: "Dropdown Value", field: fields[1] },
-        { name: "Column 3", field: fields[2], alignment: "center" },
-        { name: "Column 4", field: fields[3] }
-    ],
-    staticDataRows: records
+var dropdownChangeHandler = function(e) {
+    var dropdown = e.currentTarget;
+    var selectedIndex = dropdown.selectedIndex;
+    
+    var pos = grid.api.getRelativePosition(e);
+    var rowDef = grid.api.getRowDefinition(pos.rowIndex);
+    
+    rowDef.setData("Field XXXX", selectedIndex); // It is important to set the new data
 };
-
-var grid = document.getElementsByTagName("efx-grid")[0];
-grid.config = configObj;
 
-

You will see that the selected option is reverted back to the original option.

-

The fix

-

To avoid the problem, we have to add an event listener to our custom formatter for binding the change from users. You have added dropdownChangeHandler to fix the problem as shown below:

-
efx-grid {
+
+

Find out more information about event handling here.

+
+

Content with multiple states

+

Content with multiple states (for example, colors, disabled and invalid states) must have all states stored in the Grid. You can have as many columns' data or fields as we want in order to represent the content.

+

The example below shows input with multiple states depending on the data on other fields.

+
var formatter = function(e){
+    var cell = e.cell;
+    var rowData = e.rowData;
+    var inputElem = cell.getContent();
+    if (!inputElem) {
+        inputElem = document.createElement("input");
+    }
+    
+    var state1 = rowData["someField"];
+    if(state1) {
+        inputElem.setAttribute("disabled", "");
+    } else {
+        inputElem.removeAttribute("disabled");
+    }
+    
+    var state2 = rowData["anotherField"];
+    if(state2) {
+        inputElem.setAttribute("error", "");
+    } else {
+        inputElem.removeAttribute("error");
+    }
+    
+    inputElem.value = e.data;
+    cell.setContent(inputElem);
+};
+
+
+

Note: data is completely independent from column UIs. This means you do not have to create a column for data to exist. Data can be added or removed separately from Grid's columns.

+
+

Formatter/binding method parameters

+

Event argument binding method has the following parameter list:

+
    +
  • data : The data value corresponding to the field and row of the cell
  • +
  • cell : The cell object that provides access to the DOM element of the cell
  • +
  • rowIndex : Index of the current row of the cell being rendered
  • +
  • rowDef : The row definition object
  • +
  • rowData : The data object that stores data of the entire row
  • +
  • colIndex : Index of the current column of the cell being rendered
  • +
  • secton : The section object hosting the current column
  • +
+

Understanding row virtualization

+

The row virtualization technique is different from the lazy initialization technique, which creates more content as users scroll down through all the available rows. For example, suppose you have 10,000 rows and Grid's view port can show 20 rows. With row virtualization Grid will create content for around 24 rows (20 rows + buffer rows) throughout Grid's life cycle. With lazy initialization Grid will create content for 24 rows at first load. As users scroll down through the available rows, more and more content will be created. Eventually, all content will be created for all 10,000 rows when using the lazy initialization technique.

+

A web page will get slower as more content/elements are put into the DOM tree. So it's better to reuse the same element whenever possible.

+

Examples

+

Click the green button on the bottom right corner of the live example to see the code.

+
efx-grid {
     height: 200px;
-    margin-bottom: 40px;
 }
 
-
<efx-grid></efx-grid>
+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -91,76 +193,179 @@ 

The fix

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["id", "dropdownVal", "boolean", "text"]; -// For static data initialization -var records = []; -for (var i = 0; i < 50; i++) { - var record = {}; - record[fields[0]] = i; - record[fields[1]] = i % 4; - record[fields[2]] = i & 1 ? true : false; - record[fields[3]] = i + " Some Texts"; - records.push(record); -} - -// Show how to render custom content with an event listener -var dropdownFormatter = function(e) { +var rangeBarFormatter = function(e) { var cell = e.cell; - var dropdown = cell.getContent(); - if (!dropdown || !dropdown._myDropdown) { - dropdown = document.createElement("select"); - dropdown._myDropdown = true; - [0, 1, 2, 3].forEach(function(val) { - var option = document.createElement("option"); - option.value = val; - option.textContent = "Value " + val; - dropdown.appendChild(option); - }); + var bar = cell.getContent(); // Utilize caching + if(!bar) { + bar = document.createElement("div"); + bar.style.height = "8px"; + bar.style.position = "relative"; + bar.style.backgroundColor = "#EA7D22"; - dropdown.addEventListener("change", dropdownChangeHandler); + var indi = bar.indi = document.createElement("div"); + indi.style.position = "absolute"; + indi.style.top = "0"; + indi.style.left = "10px"; + indi.style.width = "3px"; + indi.style.height = "100%"; + indi.style.backgroundColor = "white"; + bar.appendChild(indi); } - dropdown.selectedIndex = e.data; - cell.setContent(dropdown); + cell.setContent(bar); + bar.indi.style.left = (e.data * 100)+"%"; }; -// Show how to set data based on interaction from custom content -var dropdownChangeHandler = function(e) { - var dropdown = e.currentTarget; - var selectedIndex = +(dropdown.options[dropdown.selectedIndex].value); - var pos = grid.api.getRelativePosition(e); - var rowDef = grid.api.getRowDefinition(pos.rowIndex); - rowDef.setData(grid.api.getColumnField(pos.colIndex), selectedIndex); +var capitalizer = function(e) { + e.cell.setContent(e.data.toString().toUpperCase()); +}; + +var yearDisplay = function(e) { + var cell = e.cell; + cell.setStyle("color", "black"); + cell.setStyle("background-color", "#EA7D22"); + cell.setContent("Year " + e.data.getFullYear()); }; +var fields = ["companyName", "market", "CF_LAST", "float_1", "ISODate"]; +var records = DataGenerator.generateRecords(fields, { numRows: 40 }); var configObj = { columns: [ - { name: "Row Index", field: fields[0], width: 80 }, - { name: "Dropdown", field: fields[1], binding: dropdownFormatter }, - { name: "Dropdown Value", field: fields[1] }, - { name: "Column 3", field: fields[2], alignment: "center" }, - { name: "Column 4", field: fields[3] } + {name: "Company", field: fields[0], binding: capitalizer}, + {name: "Market", field: fields[1], width: 100}, + {name: "Last", field: fields[2], width: 80}, + {name: "Buy/Sell", field: fields[3], width: 100, binding: rangeBarFormatter}, + {name: "IPO", field: fields[4], alienment: "center", binding: yearDisplay} ], staticDataRows: records }; -var grid = document.getElementsByTagName("efx-grid")[0]; +var grid = document.getElementById("grid"); grid.config = configObj;
-

Writing event listeners

-

Since the same element will be used on different rows, you cannot use closure variables that are created or given from the event arguments. Row index, column index, or cell reference must be resolved at runtime inside the event listener. You can resolve the position by using Grid's getRelativePosition() method.

-
    var dropdownChangeHandler = function(e) {
-        var dropdown = e.currentTarget;
-        var selectedIndex = +(dropdown.options[dropdown.selectedIndex].value);
+

Formatting custom content with Text Formatting Extension

+

When using Text Formatting Extension, by default, custom content will be overwritten due to the need for rendering a formatted text by the extension. To format the text inside the custom content and avoid the overriding, you will need to instruct the extension on how and where to do the formatting. See this page for more information.

+

Writing a good formatter

+

Be mindful that the binding method will be executed repeatedly and multiple times during data updates and scrolling. Performance is crucial, so you should write the code with caution. See the following guidelines for writing a good formatter.

+

Use predefined formatters

+

The most common formatters are already prewritten for you. Predefined formatters are optimized and easy to use. See this page for more details.

+

Avoid using innerHTML and innerText

+

innerHTML and innerText from native elements involve text parsing and element creation, both of which are computationally expensive. You can improve performance by avoiding using them.

+
function binding1(e) {
+    var content = document.createElement("div"); // Unneccessary creation as it will be called and created multiple times
+    content.innerHTML = "<span>" + e.data + "</span><span>2</span>"; // Slow due to text parsing and element creations
+    
+    e.cell.setContent(content);
+}
 
-        var pos = grid.api.getRelativePosition(e);
-        var rowDef = grid.api.getRowDefinition(pos.rowIndex);
-        rowDef.setData(grid.api.getColumnField(pos.colIndex), selectedIndex);
-    };
+// The above function can be re-writen as the following function
+function binding2(e) {
+    var cell = e.cell;
+    var content = cell.getContent();
+    if(!content) {
+        content = document.createElement("div");
+        var span1 = content._span1 = document.createElement("span"); 
+        var span2 = document.createElement("span");
+        span2.textContent = 2;
+        
+        content.appendChild(span1);
+        content.appendChild(span2);
+    }
+    content._span1.textContent = e.data;
+    cell.setContent(content);
+}
+
+

Avoid creating an element for simple text

+

setContent method is already optimized for simple text.

+
function binding1(e) {
+    var content = document.createElement("div"); // Unneccessary creation
+    content.textContent = e.data + " text";
+    
+    e.cell.setContent(content);
+}
+
+// The above function can be re-writen as the following function
+function binding2(e) {
+    e.cell.setContent(e.data + " text");
+}
+
+

Reuse the same content to avoid element creation

+

Bind method will be executed repeatedly and multiple times during data update and scrolling. Minimize element creation by using cache.

+
function binding1(e) {
+    var content = document.createElement("input"); // Slow
+    content.value = e.data;
+    e.cell.setContent(content);
+}
+
+// The above function can be re-writen as the following function
+function binding2(e) {
+    var cell = e.cell;
+    var content = cell.getContent(); // Get previous content
+    if(!content) {
+        content = document.createElement("input");
+    }
+    content.value = e.data;
+    cell.setContent(content);
+}
+
+

Store element in a variable for easy access

+

For complex structure content, it is faster and easier to use a variable for referencing rather than navigating through a DOM tree.

+
function binding1(e) {
+    var cell = e.cell;
+    var content = cell.getContent();
+    if(!content) {
+        content = document.createElement("div");
+        var span1 = document.createElement("span");
+        var span2 = document.createElement("span");
+        
+        content.appendChild(span1);
+        content.appendChild(span2);
+    }
+    cell.setContent(content);
+    var spans = content.getElementsByTagName("span"); // Slow
+    spans[0].textContent = e.data % 5;
+    spans[1].textContent = e.data % 3;
+}
+
+// The above function can be re-writen as the following function
+function binding2(e) {
+    var cell = e.cell;
+    var content = cell.getContent();
+    if(!content) {
+        content = document.createElement("div");
+        var span1 = content._span1 = document.createElement("span");
+        var span2 = content._span2 = document.createElement("span");
+        
+        content.appendChild(span1);
+        content.appendChild(span2);
+    }
+    content._span1.textContent = e.data % 5;
+    content._span2.textContent = e.data % 3;
+    cell.setContent(content);
+}
 
-
    -
  • currentTarget property will always give an element attached by the event listener
  • -
  • getRelativePosition() method resolves the position when the dropdown value is changed
  • -
-

See this page on how to update data.

+

Note: Cell can contain only one top level node/element (such as, single content). But a content element can have multiple nested elements.

+

Use RowDefinition object for asynchronous operation

+

When dealing with asynchronous operations such as server request and response, it is important to use the correct context and data. Row index, cell element, and page can all be changed during the waiting time. Sorting, filtering, grouping, and pagination can also affect row order. So the most reliable way to identify Grid's row is to use RowDefinition object.

+
function binding1(e) {
+    var cell = e.cell;
+    var content = cell.getContent();
+    if(!content) {
+        content = document.createElement("button");
+        content.addEventListener("click", onRequestingData);
+    }
+    cell.setContent(content);
+}
+
+function onRequestingData(e) {
+    var pos = grid.api.getRelativePosition(e);
+    var rowDef = grid.api.getRowDefinition(pos.rowIndex);
+    
+    requestServerData({}, onServerResponse.bind(null, rowDef));
+}
+
+function onServerResponse(rowDef, resp) {
+    // do something
+}
+
diff --git a/template-104.html b/template-104.html index 0f68eb56..ccec72c0 100644 --- a/template-104.html +++ b/template-104.html @@ -1,32 +1,86 @@ -

Predefined Formatter

-

Setup guide

-

Use import syntax to import the formatter into your app.

-
import { EFButtonFormatter, EFSelectFormatter } from "@refinitiv-ui/efx-grid/formatters";
+

Event handling and event listeners in formatter

+

If your custom formatter contains some input elements or controls, it's important to bind data back to Grid's internal data source when users input new data through the UI from your custom formatter. Remember, the same element will be used on different rows due to the row virtualization mechanic. If the data is changed by user actions, you need to update the change back to Grid's data source, or else the binding mechanism will replace what the user has changed with the data stored from the Grid's internal source.

+

In short, data should be updated after users interact with the UI input. getRelativePosition() method should be used to resolve current positions relative to the grid element.

+
+

APIs for data manipulation can be found here. APIs for Grid and getRelativePosition() method description can be found here.

+
+

The 'reverted' problem

+

When we don't set data back, row virtualization will not work properly and content will not be rendered properly. Suppose that we have a dropdown element in one of the grid columns. Any change that is done to the dropdown box will be reverted if we don't update the data.

+

In the live example below, try the following steps to produce the problem:

+
    +
  1. Change the selected option from the dropdown box on the first row. Remember the new selected option
  2. +
  3. Scroll down to the bottom of the grid
  4. +
  5. Scroll back up to the top of the grid
  6. +
+
efx-grid {
+    height: 200px;
+    margin-bottom: 40px;
+}
+
+
<efx-grid></efx-grid>
 
-

The basics

-

The simplest way to get the basic formatter is by calling create() without options, for example SimpleInputFormatter.create(). Then pass it to Grid using configuration, as shown below:

-
var config = {
-    columns: [{
-        name: "Company Info",
-        field: "info",
-        binding: SimpleInputFormatter.create()
-    }, {
-        name: "Currency",
-        field: "currency",
-        binding: EFSelectFormatter.create()
-    }, {
-        name: "DatePicker",
-        field: "date",
-        binding: EFDateTimePickerFormatter.create()
-    }]
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["id", "dropdownVal", "boolean", "text"];
+// For static data initialization
+var records = [];
+for (var i = 0; i < 50; i++) {
+    var record = {};
+    record[fields[0]] = i;
+    record[fields[1]] = i % 4; 
+    record[fields[2]] = i & 1 ? true : false;
+    record[fields[3]] = i + " Some Texts";
+    records.push(record);
 }
+
+var dropdownFormatter = function(e) {
+    var cell = e.cell;
+    var dropdown = cell.getContent();
+    if (!dropdown || !dropdown._myDropdown) {
+        dropdown = document.createElement("select");
+        dropdown._myDropdown = true;
+        [0, 1, 2, 3].forEach(function(val) {
+            var option = document.createElement("option");
+            option.value = val;
+            option.textContent = "Value " + val;
+            dropdown.appendChild(option);
+        });
+    }
+    
+    dropdown.selectedIndex = e.data;
+    cell.setContent(dropdown);
+};
+
+var configObj = {
+    columns: [
+        { name: "Row Index", field: fields[0], width: 80 },
+        { name: "Dropdown", field: fields[1], binding: dropdownFormatter },
+        { name: "Dropdown Value", field: fields[1] },
+        { name: "Column 3", field: fields[2], alignment: "center" },
+        { name: "Column 4", field: fields[3] }
+    ],
+    staticDataRows: records
+};
+
+var grid = document.getElementsByTagName("efx-grid")[0];
+grid.config = configObj;
 
-

Formatter with default options supports basic functioning and can be used for general usage. For input formatters, like SimpleInputFormatter, EFTextFieldFormatter, EFComboBoxFormatter, and so on, when the value has changed the new value will be saved to the dataTable of Grid. See basic formatters in the below example:

-
efx-grid {
-    height: 320px;
+

You will see that the selected option is reverted back to the original option.

+

The fix

+

To avoid the problem, we have to add an event listener to our custom formatter for binding the change from users. You have added dropdownChangeHandler to fix the problem as shown below:

+
efx-grid {
+    height: 200px;
+    margin-bottom: 40px;
 }
 
-
<efx-grid id="grid"></efx-grid>
+
<efx-grid></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -37,184 +91,168 @@ 

The basics

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var currencies = ["THB", "AUD", "USD", "YEN", "TWD"]; -DataGenerator.addFieldInfo("currency", { type: "set", members: currencies}); +var fields = ["id", "dropdownVal", "boolean", "text"]; +// For static data initialization +var records = []; +for (var i = 0; i < 50; i++) { + var record = {}; + record[fields[0]] = i; + record[fields[1]] = i % 4; + record[fields[2]] = i & 1 ? true : false; + record[fields[3]] = i + " Some Texts"; + records.push(record); +} + +// Show how to render custom content with an event listener +var dropdownFormatter = function(e) { + var cell = e.cell; + var dropdown = cell.getContent(); + if (!dropdown || !dropdown._myDropdown) { + dropdown = document.createElement("select"); + dropdown._myDropdown = true; + [0, 1, 2, 3].forEach(function(val) { + var option = document.createElement("option"); + option.value = val; + option.textContent = "Value " + val; + dropdown.appendChild(option); + }); + + dropdown.addEventListener("change", dropdownChangeHandler); + } + dropdown.selectedIndex = e.data; + cell.setContent(dropdown); +}; +// Show how to set data based on interaction from custom content +var dropdownChangeHandler = function(e) { + var dropdown = e.currentTarget; + var selectedIndex = +(dropdown.options[dropdown.selectedIndex].value); + + var pos = grid.api.getRelativePosition(e); + var rowDef = grid.api.getRowDefinition(pos.rowIndex); + rowDef.setData(grid.api.getColumnField(pos.colIndex), selectedIndex); +}; -var fields = ["number_1", "currency", "CF_NETCHNG"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { columns: [ - { - name: "SimpleLink", - field: fields[0], - alignment: "center", - binding: SimpleLinkFormatter.create() - }, - { - name: "Input", - field: fields[0], - alignment: "center", - binding: EFNumberFieldFormatter.create() - }, - { - name: "Select", - field: fields[1], - alignment: "center", - binding: EFSelectFormatter.create({ - data: currencies - }) - }, - { - name: "PercentBar", - field: fields[2], - alignment: "center", - binding: PercentBarFormatter.create() - } + { name: "Row Index", field: fields[0], width: 80 }, + { name: "Dropdown", field: fields[1], binding: dropdownFormatter }, + { name: "Dropdown Value", field: fields[1] }, + { name: "Column 3", field: fields[2], alignment: "center" }, + { name: "Column 4", field: fields[3] } ], staticDataRows: records }; -var grid = document.getElementById("grid"); +var grid = document.getElementsByTagName("efx-grid")[0]; grid.config = configObj;
-

Advance usage

-

Customizations are allowed through various options, as detailed in the following sections.

-

Common options

-

There are some options that are available for all formatters, see the below table for more details.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
attributesObjectoptionalList of attributes name and values
stylesObjectoptionalList of inline styles for the element
eventsObjectoptionalList of event names and listeners
disablingFieldstringoptionalField to be used for representing disabled attribute of the element
errorFieldstringoptionalField to be used for representing error attribute of the element
onElementRenderedFunctionoptionalEvent handler after default rendering. It is useful for additional styling
+

Writing event listeners

+

Since the same element will be used on different rows, you cannot use closure variables that are created or given from the event arguments. Row index, column index, or cell reference must be resolved at runtime inside the event listener. You can resolve the position by using Grid's getRelativePosition() method.

+
    var dropdownChangeHandler = function(e) {
+        var dropdown = e.currentTarget;
+        var selectedIndex = +(dropdown.options[dropdown.selectedIndex].value);
+
+        var pos = grid.api.getRelativePosition(e);
+        var rowDef = grid.api.getRowDefinition(pos.rowIndex);
+        rowDef.setData(grid.api.getColumnField(pos.colIndex), selectedIndex);
+    };
+
+
    +
  • currentTarget property will always give an element attached by the event listener
  • +
  • getRelativePosition() method resolves the position when the dropdown value is changed
  • +
-

Note: The available value for each option is dependent on the type of element. In the case of the EF element, more information about attributes and events can be found here.

+

See this page on how to update data.

-

Below is an example of showing a button with a label, icon, light coral background color, and listen for click and active-changed event.

-
var config = {
-    columns: [{
-        name: "Number",
-        field: "number",
-        binding: EFButtonFormatter.create({
-            label: "More detail",
-            attributes: {
-                "icon": "info"
-            },
-            styles: {
-                "background": "lightcoral"
-            },
-            events: {
-                "active-changed": function(e, context) { // Custom event exposed by the element
+

Getting column and row information from clicked content example

+
html hr {
+    margin: 5px;
+}
+textarea {
+    width: 100%;
+    height: 80px;
+    font-size: 18px;
+}
+efx-grid {
+    height: 300px;
+}
+
+
<textarea id="msg_ta"></textarea>
+<hr>
+<efx-grid></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
 
-                },
-                "click": function(e, context) { // Native events are also supported
+var onButtonClicked = function(e) {
+    var pos = grid.api.getRelativePosition(e);
+    var field = grid.api.getColumnField(pos.colIndex);
+    var rowDef = grid.api.getRowDefinition(pos.rowIndex);
+    
+    var ary = [
+        "Field: " + field,
+        "Row Data: " + JSON.stringify(rowDef.getRowData())
+    ];
+    msg_ta.textContent = ary.join("\n");
+};
 
-                }
-            },
-            onElementRendered: function(element, context) {
+var fields = ["id", "companyName", "market", "CF_NETCHNG"];
+var columnNames = ["Id", "Company Name", "Market", "Net Chng."];
+var columns = fields.map(function(f, idx) {
+    return {
+        field: f,
+        name: columnNames[idx]
+    }
+});
+columns.push({
+    field: "Field A",
+    name: "Action 1",
+    width: 70,
+    alignment: "c",
+    binding: function(e) {
+        var cell = e.cell;
+        var content = cell.getContent();
+        if(!content) {
+            content = document.createElement("button");
+            content.textContent = "A";
+            content.addEventListener("click", onButtonClicked);
+        }
+        cell.setContent(content);
+    }
+});
+columns.push({
+    field: "Field B",
+    name: "Action 2",
+    width: 70,
+    alignment: "c",
+    binding: function(e) {
+        var cell = e.cell;
+        var content = cell.getContent();
+        if(!content) {
+            content = document.createElement("button");
+            content.textContent = "B";
+            content.addEventListener("click", onButtonClicked);
+        }
+        cell.setContent(content);
+    }
+});
 
-            }
-        })
-    }]
-}
+var records = DataGenerator.generateRecords(fields, {seed: 1, rowCount: 30});
+
+var configObj = {
+    columns: columns,
+    staticDataRows: records
+};
+var grid = document.getElementsByTagName("efx-grid")[0];
+grid.config = configObj;
 
-

Event listener's parameters

-

Available parameters for all listeners are described below:

- - - - - - - - - - - - - - - - - - -
NameTypeDescription
eventEventNative event argument object
contextObjectContext object, contains all kind of information and methods
-
-

Context object also contains information about the position of the element (the same information from getRelativePosition method).

-
-

Context object methods

-

Context object also provides helper methods as shown below:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescription
getData(field)Get field value from the current row
setData(field, value)Set field value to the current row
isElementDisabled()Get data from the disablingField of the current row
disableElement(bool)Set data to the disablingField of the current row
getError()Get data from the errorField of the current row
setError(value)Set data to the errorField of the current row
-

Specific Options

-

The specific options for each formatters are separately described on each formatter page.

+

+
+
\ No newline at end of file diff --git a/template-105.html b/template-105.html index 6c623358..0f68eb56 100644 --- a/template-105.html +++ b/template-105.html @@ -1,24 +1,28 @@ -

EF Button Formatter

-

This formatter creates a ef-button without a margin. By default the text inside the button will be data from the column's field.

-

Specific options

- - - - - - - - - - - - - - - -
NameTypeAttributesDescription
labelstringoptionalText inside the button, default text is the value from the column's field
-

Example

-
efx-grid {
+

Predefined Formatter

+

Setup guide

+

Use import syntax to import the formatter into your app.

+
import { EFButtonFormatter, EFSelectFormatter } from "@refinitiv-ui/efx-grid/formatters";
+
+

The basics

+

The simplest way to get the basic formatter is by calling create() without options, for example SimpleInputFormatter.create(). Then pass it to Grid using configuration, as shown below:

+
var config = {
+    columns: [{
+        name: "Company Info",
+        field: "info",
+        binding: SimpleInputFormatter.create()
+    }, {
+        name: "Currency",
+        field: "currency",
+        binding: EFSelectFormatter.create()
+    }, {
+        name: "DatePicker",
+        field: "date",
+        binding: EFDateTimePickerFormatter.create()
+    }]
+}
+
+

Formatter with default options supports basic functioning and can be used for general usage. For input formatters, like SimpleInputFormatter, EFTextFieldFormatter, EFComboBoxFormatter, and so on, when the value has changed the new value will be saved to the dataTable of Grid. See basic formatters in the below example:

+
efx-grid {
     height: 320px;
 }
 
@@ -33,50 +37,184 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["number_1"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); +var currencies = ["THB", "AUD", "USD", "YEN", "TWD"]; +DataGenerator.addFieldInfo("currency", { type: "set", members: currencies}); +var fields = ["number_1", "currency", "CF_NETCHNG"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { columns: [ - { - name: "Data", + { + name: "SimpleLink", field: fields[0], - sort: fields[0], - alignment: "c" + alignment: "center", + binding: SimpleLinkFormatter.create() }, - { - name: "Simplest", + { + name: "Input", field: fields[0], - sort: fields[0], - alignment: "c", - binding: EFButtonFormatter.create() + alignment: "center", + binding: EFNumberFieldFormatter.create() }, - { - name: "Some options", - field: fields[0], - sort: fields[0], - alignment: "c", - binding: EFButtonFormatter.create({ - label: "", - attributes: { - icon: "cross" - }, - styles: { - width: "23px" - }, - events: { - "click": function(e) { - console.log("clicked"); - } - } + { + name: "Select", + field: fields[1], + alignment: "center", + binding: EFSelectFormatter.create({ + data: currencies }) + }, + { + name: "PercentBar", + field: fields[2], + alignment: "center", + binding: PercentBarFormatter.create() } ], - extensions: [], staticDataRows: records }; var grid = document.getElementById("grid"); grid.config = configObj;
-
\ No newline at end of file +

Advance usage

+

Customizations are allowed through various options, as detailed in the following sections.

+

Common options

+

There are some options that are available for all formatters, see the below table for more details.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
attributesObjectoptionalList of attributes name and values
stylesObjectoptionalList of inline styles for the element
eventsObjectoptionalList of event names and listeners
disablingFieldstringoptionalField to be used for representing disabled attribute of the element
errorFieldstringoptionalField to be used for representing error attribute of the element
onElementRenderedFunctionoptionalEvent handler after default rendering. It is useful for additional styling
+
+

Note: The available value for each option is dependent on the type of element. In the case of the EF element, more information about attributes and events can be found here.

+
+

Below is an example of showing a button with a label, icon, light coral background color, and listen for click and active-changed event.

+
var config = {
+    columns: [{
+        name: "Number",
+        field: "number",
+        binding: EFButtonFormatter.create({
+            label: "More detail",
+            attributes: {
+                "icon": "info"
+            },
+            styles: {
+                "background": "lightcoral"
+            },
+            events: {
+                "active-changed": function(e, context) { // Custom event exposed by the element
+
+                },
+                "click": function(e, context) { // Native events are also supported
+
+                }
+            },
+            onElementRendered: function(element, context) {
+
+            }
+        })
+    }]
+}
+
+

Event listener's parameters

+

Available parameters for all listeners are described below:

+ + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventEventNative event argument object
contextObjectContext object, contains all kind of information and methods
+
+

Context object also contains information about the position of the element (the same information from getRelativePosition method).

+
+

Context object methods

+

Context object also provides helper methods as shown below:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
getData(field)Get field value from the current row
setData(field, value)Set field value to the current row
isElementDisabled()Get data from the disablingField of the current row
disableElement(bool)Set data to the disablingField of the current row
getError()Get data from the errorField of the current row
setError(value)Set data to the errorField of the current row
+

Specific Options

+

The specific options for each formatters are separately described on each formatter page.

diff --git a/template-106.html b/template-106.html index 7584a6ff..6c623358 100644 --- a/template-106.html +++ b/template-106.html @@ -1,7 +1,24 @@ -

EF Checkbox Formatter

-

This formatter creates a ef-checkbox which will be unchecked by default.

+

EF Button Formatter

+

This formatter creates a ef-button without a margin. By default the text inside the button will be data from the column's field.

+

Specific options

+ + + + + + + + + + + + + + + +
NameTypeAttributesDescription
labelstringoptionalText inside the button, default text is the value from the column's field

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,198 +33,46 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["industry"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 25 }); - -records[1]["myCheckBoxState"] = true; // Initialize checkbox state -records[2]["myCheckBoxState"] = true; -records[3]["myCheckBoxState"] = true; +var fields = ["number_1"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { columns: [ - { - alignment: "c", - name: "", - field: "myCheckBoxState", - width: 34, - binding: EFCheckboxFormatter.create({ - events: { - "click": function(e) { - console.log("clicked"); - } - } - }) + { + name: "Data", + field: fields[0], + sort: fields[0], + alignment: "c" }, - { - name: "Grid Checkbox State", - field: "myCheckBoxState", + { + name: "Simplest", + field: fields[0], + sort: fields[0], alignment: "c", - width: 150 + binding: EFButtonFormatter.create() }, - { - name: "Industry", + { + name: "Some options", field: fields[0], - } - ], - staticDataRows: records -}; - -var grid = document.getElementById("grid"); -grid.config = configObj; -
-

Checkbox with a label

-
efx-grid {
-    height: 320px;
-}
-
-
<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "industry"];
-var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 25 });
-
-var configObj = {
-    columns: [
-        {
-            name: "Checkboxes",
-            field: "myCheckBoxState",
-            width: 150,
-            binding: EFCheckboxFormatter.create({
+            sort: fields[0],
+            alignment: "c",
+            binding: EFButtonFormatter.create({
+                label: "",
+                attributes: {
+                    icon: "cross"
+                },
+                styles: {
+                    width: "23px"
+                },
                 events: {
                     "click": function(e) {
                         console.log("clicked");
                     }
-                },
-                labelField: fields[0]
+                }
             })
-        },
-        {
-            name: "Grid Checkbox State",
-            field: "myCheckBoxState",
-            alignment: "c",
-            width: 150
-        },
-        {
-            name: "Industry",
-            field: fields[1]
-        }
-    ],
-    staticDataRows: records
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-

Checkbox and pagination

-
hr {
-    margin: 5px;
-}
-
-
<efx-grid id="grid"></efx-grid>
-<hr>
-<ef-pagination id="pagination_elem"></ef-pagination>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "industry"];
-var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 40 });
-
-var configObj = {
-    columns: [
-        {
-            name: "",
-            field: "myCheckBoxState",
-            width: 34,
-            binding: EFCheckboxFormatter.create()
-        },
-        {
-            name: "Company",
-            field: fields[0]
-        },
-        {
-            name: "Market",
-            field: fields[1]
-        },
-        {
-            name: "Industry",
-            field: fields[2]
-        }
-    ],
-    staticDataRows: records,
-    pagination: {
-        element: document.getElementById("pagination_elem"),
-        page: 1,
-        pageSize: 8
-    },
-    extensions: [new Pagination()]
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-

Multiple checkbox columns

-
efx-grid {
-    height: 320px;
-}
-
-
<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market"];
-var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 40 });
-
-var configObj = {
-    columns: [
-        {
-            name: "Company",
-            field: fields[0]
-        },
-        {
-            name: "Market",
-            field: fields[1]
-        },
-        {
-            name: "C1",
-            field: "checkState1",
-            width: 50,
-            binding: EFCheckboxFormatter.create()
-        },
-        {
-            name: "C2",
-            field: "checkState2",
-            width: 50,
-            binding: EFCheckboxFormatter.create()
-        },
-        {
-            name: "C3",
-            field: "checkState3",
-            width: 50,
-            binding: EFCheckboxFormatter.create()
         }
     ],
+    extensions: [],
     staticDataRows: records
 };
 
diff --git a/template-107.html b/template-107.html
index b1ecbb19..7584a6ff 100644
--- a/template-107.html
+++ b/template-107.html
@@ -1,24 +1,7 @@
-

EF Combo Box Formatter

-

This formatter creates a ef-combo-box without margin. Its options come from passed options.data.

-

Specific options

- - - - - - - - - - - - - - - -
NameTypeAttributesDescription
dataarrayrequiredList of items, see ef-combo-box for more detail.
+

EF Checkbox Formatter

+

This formatter creates a ef-checkbox which will be unchecked by default.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -33,31 +16,196 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var currencies = ["THB", "AUD", "USD", "YEN", "TWD"]; -DataGenerator.addFieldInfo("currency", { type: "set", members: currencies }); +var fields = ["industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 25 }); -var fields = ["number_1", "boolean", "currency"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); +records[1]["myCheckBoxState"] = true; // Initialize checkbox state +records[2]["myCheckBoxState"] = true; +records[3]["myCheckBoxState"] = true; var configObj = { columns: [ - { - name: "Column 1", - field: fields[0], - alignment: "center" + { + alignment: "c", + name: "", + field: "myCheckBoxState", + width: 34, + binding: EFCheckboxFormatter.create({ + events: { + "click": function(e) { + console.log("clicked"); + } + } + }) }, { - name: "Column 2", - field: fields[1], - alignment: "center" + name: "Grid Checkbox State", + field: "myCheckBoxState", + alignment: "c", + width: 150 }, { - name: "Select", - field: fields[2], - alignment: "center", - binding: EFComboBoxFormatter.create({ - data: currencies + name: "Industry", + field: fields[0], + } + ], + staticDataRows: records +}; + +var grid = document.getElementById("grid"); +grid.config = configObj; +
+

Checkbox with a label

+
efx-grid {
+    height: 320px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "industry"];
+var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 25 });
+
+var configObj = {
+    columns: [
+        {
+            name: "Checkboxes",
+            field: "myCheckBoxState",
+            width: 150,
+            binding: EFCheckboxFormatter.create({
+                events: {
+                    "click": function(e) {
+                        console.log("clicked");
+                    }
+                },
+                labelField: fields[0]
             })
+        },
+        {
+            name: "Grid Checkbox State",
+            field: "myCheckBoxState",
+            alignment: "c",
+            width: 150
+        },
+        {
+            name: "Industry",
+            field: fields[1]
+        }
+    ],
+    staticDataRows: records
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+

Checkbox and pagination

+
hr {
+    margin: 5px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+<hr>
+<ef-pagination id="pagination_elem"></ef-pagination>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "industry"];
+var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 40 });
+
+var configObj = {
+    columns: [
+        {
+            name: "",
+            field: "myCheckBoxState",
+            width: 34,
+            binding: EFCheckboxFormatter.create()
+        },
+        {
+            name: "Company",
+            field: fields[0]
+        },
+        {
+            name: "Market",
+            field: fields[1]
+        },
+        {
+            name: "Industry",
+            field: fields[2]
+        }
+    ],
+    staticDataRows: records,
+    pagination: {
+        element: document.getElementById("pagination_elem"),
+        page: 1,
+        pageSize: 8
+    },
+    extensions: [new Pagination()]
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+

Multiple checkbox columns

+
efx-grid {
+    height: 320px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market"];
+var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 40 });
+
+var configObj = {
+    columns: [
+        {
+            name: "Company",
+            field: fields[0]
+        },
+        {
+            name: "Market",
+            field: fields[1]
+        },
+        {
+            name: "C1",
+            field: "checkState1",
+            width: 50,
+            binding: EFCheckboxFormatter.create()
+        },
+        {
+            name: "C2",
+            field: "checkState2",
+            width: 50,
+            binding: EFCheckboxFormatter.create()
+        },
+        {
+            name: "C3",
+            field: "checkState3",
+            width: 50,
+            binding: EFCheckboxFormatter.create()
         }
     ],
     staticDataRows: records
diff --git a/template-108.html b/template-108.html
index 3791822c..b1ecbb19 100644
--- a/template-108.html
+++ b/template-108.html
@@ -1,7 +1,24 @@
-

EF DateTime Picker Formatter

-

This formatter creates ef-datetime-picker without margin.

+

EF Combo Box Formatter

+

This formatter creates a ef-combo-box without margin. Its options come from passed options.data.

+

Specific options

+ + + + + + + + + + + + + + + +
NameTypeAttributesDescription
dataarrayrequiredList of items, see ef-combo-box for more detail.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,46 +33,30 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["date"]; +var currencies = ["THB", "AUD", "USD", "YEN", "TWD"]; +DataGenerator.addFieldInfo("currency", { type: "set", members: currencies }); + +var fields = ["number_1", "boolean", "currency"]; var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { columns: [ { - name: "Data", + name: "Column 1", field: fields[0], - sortBy: fields[0], - alignment: "c", - binding: function(e) { - var value = e["data"]; - var cell = e["cell"]; - cell.setContent(value.toDateString()); - } + alignment: "center" }, - { - name: "Simplest", - field: fields[0], - sortBy: fields[0], - alignment: "c", - binding: EFDateTimePickerFormatter.create() + { + name: "Column 2", + field: fields[1], + alignment: "center" }, { - name: "Some options", - field: fields[0], - sortBy: fields[0], - alignment: "c", - binding: EFDateTimePickerFormatter.create({ - attributes: { - format: "yyyy-MM-dd" - }, - styles: { - width: "120px" - }, - events: { - "value-changed": function(e) { - // console.log("value changed: " + e.detail.value); - } - } + name: "Select", + field: fields[2], + alignment: "center", + binding: EFComboBoxFormatter.create({ + data: currencies }) } ], diff --git a/template-109.html b/template-109.html index d16a98aa..3791822c 100644 --- a/template-109.html +++ b/template-109.html @@ -1,33 +1,7 @@ -

EF Icon Formatter

-

This formatter creates a ef-icon from the column's field by default.

-
-

A full list of available icons can be found here.

-
-

Specific options

- - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
iconstring or objectoptionalIcon shown in the cell
sizestring or numberoptionalSize of an icon in pixels
+

EF DateTime Picker Formatter

+

This formatter creates ef-datetime-picker without margin.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -42,43 +16,47 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var icons = ["3d-surface", "api", "eye", "conference", "flame"]; -DataGenerator.addFieldInfo("number", { type: "number", min: 0, max: 5 }); -DataGenerator.addFieldInfo("icon", { type: "set", members: icons }); -var fields = ["number", "icon"]; +var fields = ["date"]; var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { columns: [ - { - name: "Static Icon", + { + name: "Data", + field: fields[0], + sortBy: fields[0], alignment: "c", - binding: EFIconFormatter.create({ - icon: "3d-surface", - }) + binding: function(e) { + var value = e["data"]; + var cell = e["cell"]; + cell.setContent(value.toDateString()); + } }, - { - name: "Dynamic Icon With Mapper", + { + name: "Simplest", field: fields[0], - sort: fields[0], + sortBy: fields[0], alignment: "c", - binding: EFIconFormatter.create({ - icon: { - 0: "up", - 1: "down", - 2: "left", - 3: "right", - 4: "line" - }, - size: 20 - }) + binding: EFDateTimePickerFormatter.create() }, { - name: "Dynamic Icon", - field: fields[1], - sort: fields[1], + name: "Some options", + field: fields[0], + sortBy: fields[0], alignment: "c", - binding: EFIconFormatter.create() + binding: EFDateTimePickerFormatter.create({ + attributes: { + format: "yyyy-MM-dd" + }, + styles: { + width: "120px" + }, + events: { + "value-changed": function(e) { + // console.log("value changed: " + e.detail.value); + } + } + }) } ], staticDataRows: records diff --git a/template-110.html b/template-110.html index e5daedf7..d16a98aa 100644 --- a/template-110.html +++ b/template-110.html @@ -1,7 +1,33 @@ -

EF Number Field Formatter

-

This formatter creates a ef-number-field without a margin and 100% width. By default the input's value will be the column's field.

+

EF Icon Formatter

+

This formatter creates a ef-icon from the column's field by default.

+
+

A full list of available icons can be found here.

+
+

Specific options

+ + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
iconstring or objectoptionalIcon shown in the cell
sizestring or numberoptionalSize of an icon in pixels

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,35 +42,45 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["number_1"]; +var icons = ["3d-surface", "api", "eye", "conference", "flame"]; +DataGenerator.addFieldInfo("number", { type: "number", min: 0, max: 5 }); +DataGenerator.addFieldInfo("icon", { type: "set", members: icons }); +var fields = ["number", "icon"]; var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { columns: [ - { - name: "Number", - field: fields[0], - sort: fields[0], - alignment: "c" - }, - { - name: "Simplest", - field: fields[0], - sort: fields[0], - binding: EFNumberFieldFormatter.create() + { + name: "Static Icon", + alignment: "c", + binding: EFIconFormatter.create({ + icon: "3d-surface", + }) }, { - name: "Some options (Step)", + name: "Dynamic Icon With Mapper", field: fields[0], sort: fields[0], - binding: EFNumberFieldFormatter.create({ - attributes: { - step: 100 - } + alignment: "c", + binding: EFIconFormatter.create({ + icon: { + 0: "up", + 1: "down", + 2: "left", + 3: "right", + 4: "line" + }, + size: 20 }) + }, + { + name: "Dynamic Icon", + field: fields[1], + sort: fields[1], + alignment: "c", + binding: EFIconFormatter.create() } ], - extensions: [], staticDataRows: records }; diff --git a/template-111.html b/template-111.html index d3feafa7..e5daedf7 100644 --- a/template-111.html +++ b/template-111.html @@ -1,24 +1,7 @@ -

EF Radio Button Formatter

-

This formatter creates a ef-radio-button which will be unchecked by default.

-

Specific options

- - - - - - - - - - - - - - - -
NameTypeAttributesDescription
initialIndexnumberoptionalInitial checked row index
+

EF Number Field Formatter

+

This formatter creates a ef-number-field without a margin and 100% width. By default the input's value will be the column's field.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -33,39 +16,35 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["number", "word"]; +var fields = ["number_1"]; var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { - sorting: { - sortableColumns: true - }, columns: [ - { - name: " ", - alignment: "c", - field: "radio", - width: 34, - binding: EFRadioButtonFormatter.create({ - initialIndex: 0, - events: { - "click": function(e) { - console.log("clicked"); - } - } - }) - }, - { + { name: "Number", field: fields[0], - alignment: "c", + sort: fields[0], + alignment: "c" + }, + { + name: "Simplest", + field: fields[0], + sort: fields[0], + binding: EFNumberFieldFormatter.create() }, { - name: "Description", - field: fields[1], - alignment: "c", + name: "Some options (Step)", + field: fields[0], + sort: fields[0], + binding: EFNumberFieldFormatter.create({ + attributes: { + step: 100 + } + }) } ], + extensions: [], staticDataRows: records }; diff --git a/template-112.html b/template-112.html index 344c152a..d3feafa7 100644 --- a/template-112.html +++ b/template-112.html @@ -1,5 +1,5 @@ -

EF Select Formatter

-

This formatter creates ef-select without margin. Its options come from passed options.data.

+

EF Radio Button Formatter

+

This formatter creates a ef-radio-button which will be unchecked by default.

Specific options

@@ -11,14 +11,14 @@

Specific options

- - - - + + + +
dataArrayrequiredList of items, see ef-select for more detail.initialIndexnumberoptionalInitial checked row index

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -33,48 +33,37 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var currencies = ["THB", "AUD", "USD", "YEN", "TWD"]; -DataGenerator.addFieldInfo("currency", { type: "set", members: currencies}); - -var fields = ["currency"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); +var fields = ["number", "word"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { + sorting: { + sortableColumns: true + }, columns: [ - { - name: "Data", - field: fields[0], - sort: fields[0], - alignment: "c" - }, - { - name: "Simplest", - field: fields[0], - sort: fields[0], - alignment: "c", - binding: EFSelectFormatter.create({ - entries: currencies - }) - }, - { - name: "Some options", - field: fields[0], - sort: fields[0], + { + name: " ", alignment: "c", - binding: EFSelectFormatter.create({ - data: currencies, - attributes: { - - }, - styles: { - width: "80px" - }, + field: "radio", + width: 34, + binding: EFRadioButtonFormatter.create({ + initialIndex: 0, events: { - "value-changed": function(e) { - // console.log("value changed: " + e.detail.value); + "click": function(e) { + console.log("clicked"); } } }) + }, + { + name: "Number", + field: fields[0], + alignment: "c", + }, + { + name: "Description", + field: fields[1], + alignment: "c", } ], staticDataRows: records diff --git a/template-113.html b/template-113.html index d3acf44e..344c152a 100644 --- a/template-113.html +++ b/template-113.html @@ -1,7 +1,24 @@ -

EF Text Field Formatter

-

This formatter creates a ef-text-field without a margin and 100% width. By default the input's value will be the column's field.

+

EF Select Formatter

+

This formatter creates ef-select without margin. Its options come from passed options.data.

+

Specific options

+ + + + + + + + + + + + + + + +
NameTypeAttributesDescription
dataArrayrequiredList of items, see ef-select for more detail.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,40 +33,41 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["number_1", "word"]; -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); +var currencies = ["THB", "AUD", "USD", "YEN", "TWD"]; +DataGenerator.addFieldInfo("currency", { type: "set", members: currencies}); + +var fields = ["currency"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { columns: [ { - name: "Word", - field: fields[1], - sort: fields[1] + name: "Data", + field: fields[0], + sort: fields[0], + alignment: "c" }, { name: "Simplest", - field: fields[1], - sort: fields[1], - alignment: "c", - binding: EFTextFieldFormatter.create() - }, - { - name: "Identified field", field: fields[0], sort: fields[0], alignment: "c", - binding: EFTextFieldFormatter.create({ - field: fields[1] + binding: EFSelectFormatter.create({ + entries: currencies }) }, - { + { name: "Some options", - field: fields[1], - sort: fields[1], + field: fields[0], + sort: fields[0], alignment: "c", - binding: EFTextFieldFormatter.create({ + binding: EFSelectFormatter.create({ + data: currencies, attributes: { - icon: "edit" + + }, + styles: { + width: "80px" }, events: { "value-changed": function(e) { @@ -59,7 +77,6 @@

Example

}) } ], - extensions: [], staticDataRows: records }; diff --git a/template-114.html b/template-114.html index 8fc8a44b..d3acf44e 100644 --- a/template-114.html +++ b/template-114.html @@ -1,7 +1,7 @@ -

EF Toggle Formatter

-

This formatter creates a ef-toggle. The toggle will be off by default.

+

EF Text Field Formatter

+

This formatter creates a ef-text-field without a margin and 100% width. By default the input's value will be the column's field.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,56 +16,50 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["boolean"]; +var fields = ["number_1", "word"]; var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); var configObj = { - sorting: { - sortableColumns: true - }, columns: [ - { - name: " ", + { + name: "Word", + field: fields[1], + sort: fields[1] + }, + { + name: "Simplest", + field: fields[1], + sort: fields[1], + alignment: "c", + binding: EFTextFieldFormatter.create() + }, + { + name: "Identified field", field: fields[0], sort: fields[0], alignment: "c", - width: 100, - binding: EFToggleFormatter.create({ - events: { - "click": function(e) { - // blotter.api.getDataView().log(); - } - } + binding: EFTextFieldFormatter.create({ + field: fields[1] }) }, { - name: "Label", - field: fields[0], - sort: fields[0], + name: "Some options", + field: fields[1], + sort: fields[1], alignment: "c", - width: 100, - binding: EFToggleFormatter.create({ + binding: EFTextFieldFormatter.create({ + attributes: { + icon: "edit" + }, events: { - "checked-changed": function(e) { - + "value-changed": function(e) { + // console.log("value changed: " + e.detail.value); } - }, - styles: { - width: "54px" - }, - attributes: { - label: "OFF", - "checked-label": "ON" } }) - }, - { - name: "Checked", - field: fields[0], - sort: fields[0], - alignment: "c" } ], + extensions: [], staticDataRows: records }; diff --git a/template-115.html b/template-115.html index 012f5439..8fc8a44b 100644 --- a/template-115.html +++ b/template-115.html @@ -1,54 +1,7 @@ -

Percent Bar Formatter

-

This formatter creates a percent bar.

-

Specific options

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
alignmentstringoptional"left"Possible values are l, r, c, left, right, and center
movementColorbooleanoptionaltrueIf disabled, percent bar will not use up and down colors
barColorstringoptional""Custom color for bar element
textHiddenbooleanoptionalfalseIf enabled, text label will not be shown
textWidthnumber or stringoptional56Number of pixel or percentage width
+

EF Toggle Formatter

+

This formatter creates a ef-toggle. The toggle will be off by default.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -63,42 +16,54 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["myPercent", "word"]; -var num = -100; -DataGenerator.addFieldInfo("myPercent", function(e) { - return num += 5; -}); +var fields = ["boolean"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 }); -var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 40 }); var configObj = { sorting: { sortableColumns: true }, columns: [ { - name: "Percent bar (Default)", + name: " ", field: fields[0], - alignment: "c", - binding: PercentBarFormatter.create() + sort: fields[0], + alignment: "c", + width: 100, + binding: EFToggleFormatter.create({ + events: { + "click": function(e) { + // blotter.api.getDataView().log(); + } + } + }) }, { - name: "Center alignment + No Movement Color", + name: "Label", field: fields[0], + sort: fields[0], alignment: "c", - binding: PercentBarFormatter.create({ - alignment: "c", - movementColor: false + width: 100, + binding: EFToggleFormatter.create({ + events: { + "checked-changed": function(e) { + + } + }, + styles: { + width: "54px" + }, + attributes: { + label: "OFF", + "checked-label": "ON" + } }) }, { - name: "No Label + Custom Color", + name: "Checked", field: fields[0], - alignment: "c", - binding: PercentBarFormatter.create({ - alignment: "r", - textHidden: true, - barColor: "purple" - }) + sort: fields[0], + alignment: "c" } ], staticDataRows: records diff --git a/template-116.html b/template-116.html index 040f07ef..012f5439 100644 --- a/template-116.html +++ b/template-116.html @@ -1,7 +1,54 @@ -

Simple Image Formatter

-

This formatter creates an image from the column's field by default.

+

Percent Bar Formatter

+

This formatter creates a percent bar.

+

Specific options

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDefaultDescription
alignmentstringoptional"left"Possible values are l, r, c, left, right, and center
movementColorbooleanoptionaltrueIf disabled, percent bar will not use up and down colors
barColorstringoptional""Custom color for bar element
textHiddenbooleanoptionalfalseIf enabled, text label will not be shown
textWidthnumber or stringoptional56Number of pixel or percentage width

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,29 +63,42 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["image", "s_image"]; -var records = new Array(40); -for(var i = 0; i < 40; ++i) { - var record = records[i] = {}; - record[fields[0]] = "https://dummyimage.com/40x40&text=" + i; - record[fields[1]] = "https://dummyimage.com/15x15&text=" + i; -} +var fields = ["myPercent", "word"]; +var num = -100; +DataGenerator.addFieldInfo("myPercent", function(e) { + return num += 5; +}); + +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 40 }); var configObj = { sorting: { sortableColumns: true }, columns: [ { - name: "Image", + name: "Percent bar (Default)", + field: fields[0], + alignment: "c", + binding: PercentBarFormatter.create() + }, + { + name: "Center alignment + No Movement Color", field: fields[0], alignment: "c", - binding: SimpleImageFormatter.create() + binding: PercentBarFormatter.create({ + alignment: "c", + movementColor: false + }) }, { - name: "Small Image", - field: fields[1], + name: "No Label + Custom Color", + field: fields[0], alignment: "c", - binding: SimpleImageFormatter.create() + binding: PercentBarFormatter.create({ + alignment: "r", + textHidden: true, + barColor: "purple" + }) } ], staticDataRows: records diff --git a/template-117.html b/template-117.html index ebb8222d..040f07ef 100644 --- a/template-117.html +++ b/template-117.html @@ -1,7 +1,7 @@ -

Simple Input Formatter

-

This formatter creates an input without a margin and 100% width. By default the input's value will be the column's field.

+

Simple Image Formatter

+

This formatter creates an image from the column's field by default.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,26 +16,29 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["number_1", "float_1"]; -var records = DataGenerator.generateRecords(fields, 40); - +var fields = ["image", "s_image"]; +var records = new Array(40); +for(var i = 0; i < 40; ++i) { + var record = records[i] = {}; + record[fields[0]] = "https://dummyimage.com/40x40&text=" + i; + record[fields[1]] = "https://dummyimage.com/15x15&text=" + i; +} var configObj = { + sorting: { + sortableColumns: true + }, columns: [ - { - name: "Column 1", + { + name: "Image", field: fields[0], - alignment: "center" + alignment: "c", + binding: SimpleImageFormatter.create() }, - { - name: "Column 2", + { + name: "Small Image", field: fields[1], - alignment: "center" - }, - { - name: "Input", - field: fields[0], - alignment: "center", - binding: SimpleInputFormatter.create() + alignment: "c", + binding: SimpleImageFormatter.create() } ], staticDataRows: records diff --git a/template-118.html b/template-118.html index e87d9ab6..ebb8222d 100644 --- a/template-118.html +++ b/template-118.html @@ -1,24 +1,7 @@ -

Simple Link Formatter

-

This formatter creates a link with text from the column's field by default.

-

Specific options

- - - - - - - - - - - - - - - -
NameTypeAttributesDescription
urlFieldstringoptionalField used for href attribute
+

Simple Input Formatter

+

This formatter creates an input without a margin and 100% width. By default the input's value will be the column's field.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -33,63 +16,26 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var href = "https://www.lseg.com/#"; +var fields = ["number_1", "float_1"]; +var records = DataGenerator.generateRecords(fields, 40); -var fields = ["id", "url"]; -var records = new Array(40); -for(var i = 0; i < 40; ++i) { - var record = records[i] = {}; - record[fields[0]] = i; - record[fields[1]] = "https://www.lseg.com/#" + i; -} var configObj = { - sorting: { - sortableColumns: true - }, columns: [ { - name: "Data", + name: "Column 1", field: fields[0], - alignment: "c" + alignment: "center" }, { - name: "Simplest", - field: fields[0], - alignment: "c", - binding: SimpleLinkFormatter.create({ - attributes: { - href: "https://www.lseg.com" - } - }) - }, - { - name: "Some options", - field: fields[0], - alignment: "c", - binding: SimpleLinkFormatter.create({ - label: "click here", - attributes: { - href: "https://www.lseg.com" - }, - styles: { - color: "red" - }, - events: { - "click": function(e) { - console.log("clicked"); - e.preventDefault(); - } - } - }) + name: "Column 2", + field: fields[1], + alignment: "center" }, { - name: "Dynamic URL", + name: "Input", field: fields[0], - alignment: "c", - binding: SimpleLinkFormatter.create({ - label: "see URL", - urlField: fields[1] - }) + alignment: "center", + binding: SimpleInputFormatter.create() } ], staticDataRows: records diff --git a/template-119.html b/template-119.html index b92e2959..e87d9ab6 100644 --- a/template-119.html +++ b/template-119.html @@ -1,5 +1,5 @@ -

Simple Ticker Formatter

-

This formatter creates a ticker column.

+

Simple Link Formatter

+

This formatter creates a link with text from the column's field by default.

Specific options

@@ -11,20 +11,14 @@

Specific options

- + - - - - - - - +
negativeColorurlField string optionalColor code
positiveColorstringoptionalColor codeField used for href attribute

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -39,25 +33,14 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["last", "changes", "percent", "tick_1"]; +var href = "https://www.lseg.com/#"; + +var fields = ["id", "url"]; var records = new Array(40); for(var i = 0; i < 40; ++i) { - var changes = i * (i % 7) - i % 13; - var last = 5 + i % 13; - var percent = (changes / last) * 100; - var tick; - if (percent > 0) { - tick = 1; - } else if (percent < 0) { - tick = -1; - } else { - tick = 0; - } var record = records[i] = {}; - record[fields[0]] = last; - record[fields[1]] = changes; - record[fields[2]] = percent.toFixed(2); - record[fields[3]] = tick; + record[fields[0]] = i; + record[fields[1]] = "https://www.lseg.com/#" + i; } var configObj = { sorting: { @@ -65,33 +48,47 @@

Example

}, columns: [ { - name: "Last", + name: "Data", field: fields[0], alignment: "c" }, { - name: "Changes", - field: fields[1], - alignment: "c", - }, - { - name: "Changes %", - field: fields[2], + name: "Simplest", + field: fields[0], alignment: "c", + binding: SimpleLinkFormatter.create({ + attributes: { + href: "https://www.lseg.com" + } + }) }, { - name: "Default", - field: fields[3], + name: "Some options", + field: fields[0], alignment: "c", - binding: SimpleTickerFormatter.create() + binding: SimpleLinkFormatter.create({ + label: "click here", + attributes: { + href: "https://www.lseg.com" + }, + styles: { + color: "red" + }, + events: { + "click": function(e) { + console.log("clicked"); + e.preventDefault(); + } + } + }) }, { - name: "Custom", - field: fields[3], + name: "Dynamic URL", + field: fields[0], alignment: "c", - binding: SimpleTickerFormatter.create({ - negativeColor: "#FF6333", - positiveColor: "#607EFF", + binding: SimpleLinkFormatter.create({ + label: "see URL", + urlField: fields[1] }) } ], diff --git a/template-120.html b/template-120.html index 1299e4b7..b92e2959 100644 --- a/template-120.html +++ b/template-120.html @@ -1,7 +1,30 @@ -

Simple Toggle Formatter

-

This formatter creates a toggle column with a default "eye" icon.

+

Simple Ticker Formatter

+

This formatter creates a ticker column.

+

Specific options

+ + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
negativeColorstringoptionalColor code
positiveColorstringoptionalColor code

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -16,12 +39,25 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["toggle", "number_1"]; +var fields = ["last", "changes", "percent", "tick_1"]; var records = new Array(40); for(var i = 0; i < 40; ++i) { + var changes = i * (i % 7) - i % 13; + var last = 5 + i % 13; + var percent = (changes / last) * 100; + var tick; + if (percent > 0) { + tick = 1; + } else if (percent < 0) { + tick = -1; + } else { + tick = 0; + } var record = records[i] = {}; - record[fields[0]] = i % 2 === 0; - record[fields[1]] = i; + record[fields[0]] = last; + record[fields[1]] = changes; + record[fields[2]] = percent.toFixed(2); + record[fields[3]] = tick; } var configObj = { sorting: { @@ -29,15 +65,34 @@

Example

}, columns: [ { - name: "", + name: "Last", field: fields[0], - alignment: "c", - binding: SimpleToggleFormatter.create() + alignment: "c" }, { - name: "Column 2", + name: "Changes", field: fields[1], alignment: "c", + }, + { + name: "Changes %", + field: fields[2], + alignment: "c", + }, + { + name: "Default", + field: fields[3], + alignment: "c", + binding: SimpleTickerFormatter.create() + }, + { + name: "Custom", + field: fields[3], + alignment: "c", + binding: SimpleTickerFormatter.create({ + negativeColor: "#FF6333", + positiveColor: "#607EFF", + }) } ], staticDataRows: records diff --git a/template-121.html b/template-121.html index 5cc0bef0..1299e4b7 100644 --- a/template-121.html +++ b/template-121.html @@ -1,9 +1,7 @@ -

Text Formatter

-

This formatter creates a simple div element with text from the column's field by default. The div element can be modified in the handler (for example, onElementRendered) and passed through configuration object for multiple use cases.

-

Specific options

-

The purpose of this formatter is creating a generic element for further modifications, so there are no specific options.

+

Simple Toggle Formatter

+

This formatter creates a toggle column with a default "eye" icon.

Example

-
efx-grid {
+
efx-grid {
     height: 320px;
 }
 
@@ -18,35 +16,28 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["number_1", "word", "float_1"]; -var records = DataGenerator.generateRecords(fields, 40); - +var fields = ["toggle", "number_1"]; +var records = new Array(40); +for(var i = 0; i < 40; ++i) { + var record = records[i] = {}; + record[fields[0]] = i % 2 === 0; + record[fields[1]] = i; +} var configObj = { + sorting: { + sortableColumns: true + }, columns: [ { - name: "Column 1", + name: "", field: fields[0], - alignment: "right", - binding: TextFormatter.create() + alignment: "c", + binding: SimpleToggleFormatter.create() }, { name: "Column 2", field: fields[1], - alignment: "center", - binding: TextFormatter.create({ - styles: { - "backgroundColor": "thistle" - } - }) - }, - { - name: "Big Text", - field: fields[2], - binding: TextFormatter.create({ - styles: { - "fontSize": "1.5em" - } - }) + alignment: "c", } ], staticDataRows: records @@ -55,9 +46,4 @@

Example

var grid = document.getElementById("grid"); grid.config = configObj;
-

Formatting predefined formatter using Text Formatting Extension

-

When using Text Formatting Extension, by default, predefined formatter will be overwritten due to the need for rendering a formatted text by the extension. To format the text inside predefined formatter and avoid the overriding, you will need to instruct the extension on how and where to do the formatting. See this page for more information.

-

In this case, you can use onElementRendered and Text Formatting Extension to do the formatting.

-
-
-
\ No newline at end of file +
\ No newline at end of file diff --git a/template-122.html b/template-122.html index 777eb93e..5cc0bef0 100644 --- a/template-122.html +++ b/template-122.html @@ -1,17 +1,13 @@ -

Adding Header and Footer Sections

-

Additional header and footer sections can be added, and are automatically frozen. Both methods (header and footer) return the new section (with the row count of one), which can then be populated programmatically.

+

Text Formatter

+

This formatter creates a simple div element with text from the column's field by default. The div element can be modified in the handler (for example, onElementRendered) and passed through configuration object for multiple use cases.

+

Specific options

+

The purpose of this formatter is creating a generic element for further modifications, so there are no specific options.

Example

-
html hr {
-    margin: 5px;
-}
-efx-grid {
-    height: 200px;
+
efx-grid {
+    height: 320px;
 }
 
-
<button id="header_btn">Add Header Section</button>
-<button id="footer_btn">Add Footer Section</button>
-<hr>
-<efx-grid id="grid"></efx-grid>
+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -22,40 +18,46 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 6 }); +var fields = ["number_1", "word", "float_1"]; +var records = DataGenerator.generateRecords(fields, 40); + var configObj = { columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80}, - {name: "Net. Chng", field: fields[3], width: 80}, - {name: "Industry", field: fields[4]} + { + name: "Column 1", + field: fields[0], + alignment: "right", + binding: TextFormatter.create() + }, + { + name: "Column 2", + field: fields[1], + alignment: "center", + binding: TextFormatter.create({ + styles: { + "backgroundColor": "thistle" + } + }) + }, + { + name: "Big Text", + field: fields[2], + binding: TextFormatter.create({ + styles: { + "fontSize": "1.5em" + } + }) + } ], staticDataRows: records }; var grid = document.getElementById("grid"); grid.config = configObj; - -document.getElementById("header_btn").addEventListener("click", function() { - var newSection = grid.api.addHeaderSection("My_Header"); - if(newSection) { // New section can only be created, if the name of the section is unique - newSection.setCellColSpan(0, 0, 5); - var cell = newSection.getCell(0, 0); - cell.setContent("Header"); - } -}); - -document.getElementById("footer_btn").addEventListener("click", function() { - var newSection = grid.api.addFooterSection("My_Footer"); - if(newSection) { // New section can only be created, if the name of the section is unique - newSection.getCell(0, 0).setContent("Footer"); - newSection.getCell(1, 0).setContent("100"); - newSection.getCell(2, 0).setContent("200"); - newSection.getCell(3, 0).setContent("300"); - newSection.getCell(4, 0).setContent("400"); - } -});
- \ No newline at end of file +

Formatting predefined formatter using Text Formatting Extension

+

When using Text Formatting Extension, by default, predefined formatter will be overwritten due to the need for rendering a formatted text by the extension. To format the text inside predefined formatter and avoid the overriding, you will need to instruct the extension on how and where to do the formatting. See this page for more information.

+

In this case, you can use onElementRendered and Text Formatting Extension to do the formatting.

+
+
+
\ No newline at end of file diff --git a/template-123.html b/template-123.html index 56b3cec3..777eb93e 100644 --- a/template-123.html +++ b/template-123.html @@ -1,147 +1,17 @@ -

General Concepts and Row Expansion APIs

-

Row expansion is an extra row that is extended directly from a normal row. It's a great place to show extra information which cannot normally be shown on a single row.

-

It looks just like a normal row but, unlike a normal row, it has no data from the main data table associated with it. This means that the states or data of the row expansion have to come from the expanded row. Grid will not perform sorting or filtering on the row expansion, as it has no data.

-

In effect, row expansion is completely different from row grouping, where rows are grouped based on their data. Row expansion is tightly connected to the expanded row and cannot be separated. When the expanded row is moved, the row expansion is also moved. So, be aware that operations like sorting, filtering, or pagination can still have an impact on how row expansion is displayed.

-

To add a row expansion, call addRowExpansion(rowId) or toggleRowExpansion(rowId) from Grid's data view. rowId is the row ID of the row to be expanded.

-

To remove all row expansions at once, use removeAllRowExpansions().

-

To get existing rows with an expansion, use getRowsWithExpansion().

-

To render content on the row expansion, define renderer property of rowExpansion on the grid configuration object, like so:

-
var configObj = {
-    //...
-    rowExpansionBinding: function (e) {
-        var rowIndex = e["rowIndex"];
-        var section = e["section"];
-        
-        if(e.rowExpansion) {
-            // render
-            var rowData = e.originalRowData;
-            var cell = section.stretchCell(0, rowIndex);
-            var str = "expanded from row \"" + rowData["col1"] + ", " + rowData["col2"] + ", " + rowData["col3"] + "\"";
-            cell.setContent(str);
-            cell.setStyle("background-color", "lightblue");
-        } else {
-            //dispose
-            var cell = section.stretchCell(0, rowIndex, false);
-            cell.setStyle("background-color", "");
-        }
-    },
-    //...
-};
-
-
-

Note: the same cell element is used for both normal row and row expansion due to the virtualization technique. Any custom style has to be removed using the dispose part.

-
-

The example below shows how to create row expansion when clicking on a normal row. It also shows how to save and load row expansion states.

-
efx-grid {
-    height: 200px;
-}
-html hr {
+

Adding Header and Footer Sections

+

Additional header and footer sections can be added, and are automatically frozen. Both methods (header and footer) return the new section (with the row count of one), which can then be populated programmatically.

+

Example

+
html hr {
     margin: 5px;
 }
-
-
<button id="save_states">Save</button>
-<button id="load_states">Load</button>
-<button id="clear_row_expan">Clear all row expansions</button>
-<hr>
-<efx-grid id="grid"></efx-grid>
-<hr>
-<pre id="msg"></pre>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 10 });
-
-function onCellCliked(e) {
-    var pos = grid.api.getRelativePosition(e);
-    if (pos.sectionType === "content") { // Prevent clicking on header section
-        var dv = grid.api.getDataView();
-        dv.toggleRowExpansion(pos.rowIndex);
-    }
-}
-
-document.getElementById("save_states").addEventListener("click", function () {
-    var dv = grid.api.getDataView();
-    var rowWithExpansions = dv.getRowsWithExpansion();
-    var rowIds = rowWithExpansions.filter(function (id) {
-        return id;
-    });
-
-    msg.textContent = "Row Ids saved:\n" + JSON.stringify(rowIds, null, 4);
-    sessionStorage.setItem("row_expansion_data", JSON.stringify(rowIds));
-});
-
-document.getElementById("load_states").addEventListener("click", function () {
-    // Initial row expansion from rowId
-    var dv = grid.api.getDataView();
-    var data = sessionStorage.getItem("row_expansion_data");
-    msg.textContent = "Data loaded: " + data;
-    const rowIds = JSON.parse(data);
-    dv.removeAllRowExpansions();
-    for (var rowId of rowIds) {
-        dv.addRowExpansion(rowId);
-    }
-});
-
-document.getElementById("clear_row_expan").addEventListener("click", function () {
-    var dv = grid.api.getDataView();
-    dv.removeAllRowExpansions();
-    msg.textContent = "Row expansions are cleared";
-});
-
-var configObj = {
-    sorting: {
-        sortableColumns: true
-    },
-    columns: [
-        {name: "Company", field: fields[0]},
-        {name: "Market", field: fields[1], width: 120},
-        {name: "Last", field: fields[2], width: 100},
-        {name: "Net. Chng", field: fields[3], width: 100},
-        {name: "Industry", field: fields[4]}
-    ],
-    rowExpansionBinding: function(e) {
-        var rowIndex = e["rowIndex"];
-        var section = e["section"];
-        var colCount = section.getColumnCount();
-        if (e.rowExpansion) {
-            for (var c = 0; c < colCount; ++c) {
-                var cell = section.getCell(c, rowIndex);
-                cell.setContent("Row Expansion_" + c);
-                cell.setStyle("backgroundColor", "#cc7755");
-            }
-        } else {
-            for (var c = 0; c < colCount; ++c) {
-                var cell = section.getCell(c, rowIndex);
-                cell.setStyle("backgroundColor", "");
-            }
-        }
-    },
-    staticDataRows: records
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-grid.addEventListener("click", onCellCliked);
-
-

Managing states for row expansion

-

Since row expansion has no row data to hold its state, the data has to be stored on the expanded row. The example below shows how you can have two different types of content based on the button being clicked.

-
efx-grid {
+efx-grid {
     height: 200px;
 }
-html hr {
-    margin: 5px;
-}
 
-
<efx-grid id="grid"></efx-grid>
+
<button id="header_btn">Add Header Section</button>
+<button id="footer_btn">Add Footer Section</button>
+<hr>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -153,220 +23,39 @@ 

General Concepts and Row Expans Please see the document for further information. ---------------------------------------------------------------------------*/ var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); - -var buttonFormatter = function (e) { - var cell = e["cell"]; - var content = cell.getContent(); - if (!content || !cell._buttons) { - var buttonsContainer = (cell._buttons = document.createElement("div")); - var firstButton = document.createElement("ef-button"); - firstButton.icon = "edit"; - firstButton.addEventListener("click", onFirstClickButton); - - var secondButton = document.createElement("ef-button"); - secondButton.icon = "filter"; - secondButton.addEventListener("click", onSecondClickButton); - buttonsContainer.appendChild(firstButton); - buttonsContainer.appendChild(secondButton); - } - cell.setContent(cell._buttons); -}; - -var onFirstClickButton = function (e) { - var pos = grid.api.getRelativePosition(e); - var dv = grid.api.getDataView(); - - // Save the state to the expanded row - dv.setDataAt(pos.rowIndex, "My_Clicked_Button", 1); - - dv.toggleRowExpansion(pos.rowIndex); -}; - -var onSecondClickButton = function (e) { - var pos = grid.api.getRelativePosition(e); - var dv = grid.api.getDataView(); - - // Save the state to the expanded row - dv.setDataAt(pos.rowIndex, "My_Clicked_Button", 2); - - dv.toggleRowExpansion(pos.rowIndex); -}; - +var records = DataGenerator.generateRecords(fields, { numRows: 6 }); var configObj = { columns: [ - { - name: "Buttons", - field: "btnClicked", - binding: buttonFormatter, - width: 80, - alignment: "center" - }, {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 120}, - {name: "Last", field: fields[2], width: 100}, - {name: "Net. Chng", field: fields[3], width: 100}, + {name: "Market", field: fields[1], width: 100}, + {name: "Last", field: fields[2], width: 80}, + {name: "Net. Chng", field: fields[3], width: 80}, {name: "Industry", field: fields[4]} ], - rowExpansionBinding: function(e) { - var rowIndex = e["rowIndex"]; - var section = e["section"]; - if (e.rowExpansion) { - // render - var cell = section.stretchCell(0, rowIndex, true); - var rowData = e.originalRowData; - if (rowData["My_Clicked_Button"] === 1) { - cell.setContent("First button was clicked"); - } else { - cell.setContent("Second button was clicked"); - } - cell.setStyle("backgroundColor", "#cc7755"); - cell.setStyle("textAlign", "left"); - } else { - // dispose - var cell = section.stretchCell(0, rowIndex, false); - cell.setStyle("backgroundColor", ""); - cell.setStyle("textAlign", ""); - } - }, staticDataRows: records }; var grid = document.getElementById("grid"); grid.config = configObj; -

-

Multiple row expansions from a single row

-

You can specify the number of row expansions to be added on a single row by passing the number as the third parameter for toggleRowExpansion(rowId, null, numRows).

-
-

Note that row expansion has no row data. So the entire data set for multiple row expansions have to be stored on the expanded row. Luckily, any data structure can be stored on the row data. For instance, you can have an array of objects representing states of row expansions, like so:

-
-
dv.setData(rowId, "My_Row_Expansion_States", [ 
-    {name: "Row 1", value: 1},
-    {name: "Row 2", value: 2},
-    // ...
-]);
-
-

Handling asynchronous content

-

Rows can be shifted and data can be updated during the asynchronous process, such as waiting for a response from a server. It is a good idea to always use the row ID for referencing a row and not assume that rows or elements stay in the same place.

-

The example below shows how to render custom content with asynchronous data. The row ID is retrieved and used for referencing after the server response.

-
efx-grid {
-    height: 200px;
-}
-html hr {
-    margin: 5px;
-}
-
-
<efx-grid id="grid"></efx-grid>
-<hr>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
 
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var records = DataGenerator.generateRecords(fields, { numRows: 10 });
-
-var onRowExpansionBinding = function(e) {
-    var rowData = e.originalRowData;
-    var rowIndex = e["rowIndex"];
-    var section = e["section"];
-    if (e.rowExpansion && rowData) {
-        // render
-        var cell = section.stretchCell(0, rowIndex, true);
-        cell.setStyle("backgroundColor", "#cc7755");
-        section.setRowHeight(rowIndex, 72); // Customized height
-
-        var expContent = cell.getContent();
-        if (!expContent || !expContent._myExpansion) {
-            expContent = document.createElement("div");
-            expContent._myExpansion = true;
-
-            var firstLine = expContent._firstLine = document.createElement("div");
-            var secondLine = expContent._secondLine = document.createElement("div");
-            var loader = expContent._loader = document.createElement("ef-loader");
-            var button = document.createElement("button");
-            button.textContent = "Column & Row Index";
-            button.addEventListener("click", function (e) {
-                var pos = grid.api.getRelativePosition(e);
-                alert(pos.colIndex + ", " + pos.rowIndex);
-            });
-
-            secondLine.appendChild(button);
-
-            expContent.appendChild(firstLine);
-            expContent.appendChild(secondLine);
-            expContent.appendChild(loader);
-        }
-
-        var rowData = e.originalRowData;
-        if (rowData["My_Expansion_Status"] === "loading") {
-            expContent._firstLine.style.display = "none";
-            expContent._secondLine.style.display = "none";
-            expContent._loader.style.display = "";
-        } else {
-            expContent._firstLine.style.display = "";
-            expContent._secondLine.style.display = "";
-            expContent._loader.style.display = "none";
-        }
-        cell.setContent(expContent);
-    } else {
-        // dispose
-        var cell = section.stretchCell(0, rowIndex, false);
-        cell.setStyle("backgroundColor", "");
-        section.setRowHeight(rowIndex, section.getDefaultRowHeight()); // Default height
+document.getElementById("header_btn").addEventListener("click", function() {
+    var newSection = grid.api.addHeaderSection("My_Header");
+    if(newSection) { // New section can only be created, if the name of the section is unique
+        newSection.setCellColSpan(0, 0, 5);
+        var cell = newSection.getCell(0, 0);
+        cell.setContent("Header");
     }
-}
+});
 
-var onCellCliked = function(e) {
-    var pos = grid.api.getRelativePosition(e);
-    if (pos.sectionType === "content") { // Prevent clicking on header section
-        var rowIndex = pos.rowIndex;
-        var rowDef = grid.api.getRowDefinition(rowIndex);
-        if (rowDef) { // Prevent clicking on expanded row
-            var rowId = rowDef.getRowId();
-            var dv = grid.api.getDataView();
-            if (!dv.isRowExpansion(rowId)) {
-                if (rowDef.getData("My_Expansion_Status") == null) {
-                    rowDef.setData("My_Expansion_Status", "loading");
-                    // Simulate delay from data request
-                    setTimeout(onServerResponse.bind(null, dv, rowDef), 3000); // Asynchronous
-                }
-                dv.toggleRowExpansion(pos.rowIndex);
-            }
-        }
-    }
-};
-var onServerResponse = function(dv, rowDef) {
-    if (!dv.isRowExpansion(rowDef.getRowId())) {
-        rowDef.setData("My_Expansion_Status", "data received");
+document.getElementById("footer_btn").addEventListener("click", function() {
+    var newSection = grid.api.addFooterSection("My_Footer");
+    if(newSection) { // New section can only be created, if the name of the section is unique
+        newSection.getCell(0, 0).setContent("Footer");
+        newSection.getCell(1, 0).setContent("100");
+        newSection.getCell(2, 0).setContent("200");
+        newSection.getCell(3, 0).setContent("300");
+        newSection.getCell(4, 0).setContent("400");
     }
-    grid.api.getCoreGrid().requestRowRefresh(); // WORKAROUND: Force re-rendering
-};
-
-var configObj = {
-    columnReorder: true,
-    sorting: {
-        sortableColumns: true
-    },
-    columns: [
-        {name: "Company", field: fields[0]},
-        {name: "Market", field: fields[1], width: 120},
-        {name: "Last", field: fields[2], width: 100},
-        {name: "Net. Chng", field: fields[3], width: 100},
-        {name: "Industry", field: fields[4]}
-    ],
-    rowExpansionBinding: onRowExpansionBinding,
-    staticDataRows: records
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-grid.addEventListener("click", onCellCliked);
+});
 
\ No newline at end of file diff --git a/template-124.html b/template-124.html index 47400a7c..56b3cec3 100644 --- a/template-124.html +++ b/template-124.html @@ -1,32 +1,51 @@ -

Row Grouping

-
-

Note: Built-in row grouping is deprecated in favor of the Row Grouping Extension. In terms of both functionalities and UIs, the extension provides more control and flexibility over the current APIs.

-
-

Row grouping can be done by using the Row Grouping Extension. To do the grouping, you will need to provide grouping criteria to the groupBy property of the rowGrouping option in the grid configuration object.

+

General Concepts and Row Expansion APIs

+

Row expansion is an extra row that is extended directly from a normal row. It's a great place to show extra information which cannot normally be shown on a single row.

+

It looks just like a normal row but, unlike a normal row, it has no data from the main data table associated with it. This means that the states or data of the row expansion have to come from the expanded row. Grid will not perform sorting or filtering on the row expansion, as it has no data.

+

In effect, row expansion is completely different from row grouping, where rows are grouped based on their data. Row expansion is tightly connected to the expanded row and cannot be separated. When the expanded row is moved, the row expansion is also moved. So, be aware that operations like sorting, filtering, or pagination can still have an impact on how row expansion is displayed.

+

To add a row expansion, call addRowExpansion(rowId) or toggleRowExpansion(rowId) from Grid's data view. rowId is the row ID of the row to be expanded.

+

To remove all row expansions at once, use removeAllRowExpansions().

+

To get existing rows with an expansion, use getRowsWithExpansion().

+

To render content on the row expansion, define renderer property of rowExpansion on the grid configuration object, like so:

var configObj = {
-    ...
-    rowGrouping: {
-        groupBy: ["field1", "criteria"],
+    //...
+    rowExpansionBinding: function (e) {
+        var rowIndex = e["rowIndex"];
+        var section = e["section"];
+        
+        if(e.rowExpansion) {
+            // render
+            var rowData = e.originalRowData;
+            var cell = section.stretchCell(0, rowIndex);
+            var str = "expanded from row \"" + rowData["col1"] + ", " + rowData["col2"] + ", " + rowData["col3"] + "\"";
+            cell.setContent(str);
+            cell.setStyle("background-color", "lightblue");
+        } else {
+            //dispose
+            var cell = section.stretchCell(0, rowIndex, false);
+            cell.setStyle("background-color", "");
+        }
     },
-    ...
-}
+    //...
+};
 
-

Example

-
efx-grid {
-    height: 320px;
+
+

Note: the same cell element is used for both normal row and row expansion due to the virtualization technique. Any custom style has to be removed using the dispose part.

+
+

The example below shows how to create row expansion when clicking on a normal row. It also shows how to save and load row expansion states.

+
efx-grid {
+    height: 200px;
+}
+html hr {
+    margin: 5px;
 }
 
-
<big>Group By:</big>
-<button id="g1_btn">Market</button>
-<button id="g2_btn">Industry</button>
-<button id="g23_btn">Market and Industry</button>
-<button id="clear_btn">Reset Grouping</button>
-<br><br>
-<big>Expand:</big>
-<button id="expand_btn">Expand All Groups</button>
-<button id="collapse_btn">Collapse All Groups</button>
-<br><br>
+
<button id="save_states">Save</button>
+<button id="load_states">Load</button>
+<button id="clear_row_expan">Clear all row expansions</button>
+<hr>
 <efx-grid id="grid"></efx-grid>
+<hr>
+<pre id="msg"></pre>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -37,51 +56,317 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var rowGroupingExt = new RowGrouping(); - var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; - var records = DataGenerator.generateRecords(fields, { numRows: 100 }); - var configObj = { - rowGrouping: { - groupBy: ["market", "industry"], - headerBinding: function(e) { - e.cell.setContent(e.groupId + " (" + e.dataSource.getAllRowIds().length + ")"); - }, - groupSortLogic: function(a, b) { // Optional - return (a < b ? -1 : ( a > b ? 1 : 0)); - }, - headerSpanning: true // Optional - }, - columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80}, - {name: "Net. Chng", field: fields[3], width: 80}, - {name: "Industry", field: fields[4]} - ], - staticDataRows: records, - extensions: [rowGroupingExt] - }; - - var grid = document.getElementById("grid"); - grid.config = configObj; - - g1_btn.addEventListener("click", function(e) { - rowGroupingExt.groupBy(fields[1]); - }); - g2_btn.addEventListener("click", function(e) { - rowGroupingExt.groupBy(fields[4]); - }); - g23_btn.addEventListener("click", function(e) { - rowGroupingExt.groupBy([fields[1], fields[4]]); - }); - clear_btn.addEventListener("click", function(e) { - rowGroupingExt.groupBy(null); - }); - expand_btn.addEventListener("click", function(e) { - rowGroupingExt.expandAll(); - }); - collapse_btn.addEventListener("click", function(e) { - rowGroupingExt.collapseAll(); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 10 }); + +function onCellCliked(e) { + var pos = grid.api.getRelativePosition(e); + if (pos.sectionType === "content") { // Prevent clicking on header section + var dv = grid.api.getDataView(); + dv.toggleRowExpansion(pos.rowIndex); + } +} + +document.getElementById("save_states").addEventListener("click", function () { + var dv = grid.api.getDataView(); + var rowWithExpansions = dv.getRowsWithExpansion(); + var rowIds = rowWithExpansions.filter(function (id) { + return id; }); + + msg.textContent = "Row Ids saved:\n" + JSON.stringify(rowIds, null, 4); + sessionStorage.setItem("row_expansion_data", JSON.stringify(rowIds)); +}); + +document.getElementById("load_states").addEventListener("click", function () { + // Initial row expansion from rowId + var dv = grid.api.getDataView(); + var data = sessionStorage.getItem("row_expansion_data"); + msg.textContent = "Data loaded: " + data; + const rowIds = JSON.parse(data); + dv.removeAllRowExpansions(); + for (var rowId of rowIds) { + dv.addRowExpansion(rowId); + } +}); + +document.getElementById("clear_row_expan").addEventListener("click", function () { + var dv = grid.api.getDataView(); + dv.removeAllRowExpansions(); + msg.textContent = "Row expansions are cleared"; +}); + +var configObj = { + sorting: { + sortableColumns: true + }, + columns: [ + {name: "Company", field: fields[0]}, + {name: "Market", field: fields[1], width: 120}, + {name: "Last", field: fields[2], width: 100}, + {name: "Net. Chng", field: fields[3], width: 100}, + {name: "Industry", field: fields[4]} + ], + rowExpansionBinding: function(e) { + var rowIndex = e["rowIndex"]; + var section = e["section"]; + var colCount = section.getColumnCount(); + if (e.rowExpansion) { + for (var c = 0; c < colCount; ++c) { + var cell = section.getCell(c, rowIndex); + cell.setContent("Row Expansion_" + c); + cell.setStyle("backgroundColor", "#cc7755"); + } + } else { + for (var c = 0; c < colCount; ++c) { + var cell = section.getCell(c, rowIndex); + cell.setStyle("backgroundColor", ""); + } + } + }, + staticDataRows: records +}; + +var grid = document.getElementById("grid"); +grid.config = configObj; + +grid.addEventListener("click", onCellCliked); +
+

Managing states for row expansion

+

Since row expansion has no row data to hold its state, the data has to be stored on the expanded row. The example below shows how you can have two different types of content based on the button being clicked.

+
efx-grid {
+    height: 200px;
+}
+html hr {
+    margin: 5px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { numRows: 10 });
+
+var buttonFormatter = function (e) {
+    var cell = e["cell"];
+    var content = cell.getContent();
+    if (!content || !cell._buttons) {
+        var buttonsContainer = (cell._buttons = document.createElement("div"));
+        var firstButton = document.createElement("ef-button");
+        firstButton.icon = "edit";
+        firstButton.addEventListener("click", onFirstClickButton);
+
+        var secondButton = document.createElement("ef-button");
+        secondButton.icon = "filter";
+        secondButton.addEventListener("click", onSecondClickButton);
+        buttonsContainer.appendChild(firstButton);
+        buttonsContainer.appendChild(secondButton);
+    }
+    cell.setContent(cell._buttons);
+};
+
+var onFirstClickButton = function (e) {
+    var pos = grid.api.getRelativePosition(e);
+    var dv = grid.api.getDataView();
+
+    // Save the state to the expanded row
+    dv.setDataAt(pos.rowIndex, "My_Clicked_Button", 1);
+
+    dv.toggleRowExpansion(pos.rowIndex);
+};
+
+var onSecondClickButton = function (e) {
+    var pos = grid.api.getRelativePosition(e);
+    var dv = grid.api.getDataView();
+
+    // Save the state to the expanded row
+    dv.setDataAt(pos.rowIndex, "My_Clicked_Button", 2);
+
+    dv.toggleRowExpansion(pos.rowIndex);
+};
+
+var configObj = {
+    columns: [
+        {
+            name: "Buttons",
+            field: "btnClicked",
+            binding: buttonFormatter,
+            width: 80,
+            alignment: "center"
+        },
+        {name: "Company", field: fields[0]},
+        {name: "Market", field: fields[1], width: 120},
+        {name: "Last", field: fields[2], width: 100},
+        {name: "Net. Chng", field: fields[3], width: 100},
+        {name: "Industry", field: fields[4]}
+    ],
+    rowExpansionBinding: function(e) {
+        var rowIndex = e["rowIndex"];
+        var section = e["section"];
+        if (e.rowExpansion) {
+            // render
+            var cell = section.stretchCell(0, rowIndex, true);
+            var rowData = e.originalRowData;
+            if (rowData["My_Clicked_Button"] === 1) {
+                cell.setContent("First button was clicked");
+            } else {
+                cell.setContent("Second button was clicked");
+            }
+            cell.setStyle("backgroundColor", "#cc7755");
+            cell.setStyle("textAlign", "left");
+        } else {
+            // dispose
+            var cell = section.stretchCell(0, rowIndex, false);
+            cell.setStyle("backgroundColor", "");
+            cell.setStyle("textAlign", "");
+        }
+    },
+    staticDataRows: records
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+

Multiple row expansions from a single row

+

You can specify the number of row expansions to be added on a single row by passing the number as the third parameter for toggleRowExpansion(rowId, null, numRows).

+
+

Note that row expansion has no row data. So the entire data set for multiple row expansions have to be stored on the expanded row. Luckily, any data structure can be stored on the row data. For instance, you can have an array of objects representing states of row expansions, like so:

+
+
dv.setData(rowId, "My_Row_Expansion_States", [ 
+    {name: "Row 1", value: 1},
+    {name: "Row 2", value: 2},
+    // ...
+]);
+
+

Handling asynchronous content

+

Rows can be shifted and data can be updated during the asynchronous process, such as waiting for a response from a server. It is a good idea to always use the row ID for referencing a row and not assume that rows or elements stay in the same place.

+

The example below shows how to render custom content with asynchronous data. The row ID is retrieved and used for referencing after the server response.

+
efx-grid {
+    height: 200px;
+}
+html hr {
+    margin: 5px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+<hr>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { numRows: 10 });
+
+var onRowExpansionBinding = function(e) {
+    var rowData = e.originalRowData;
+    var rowIndex = e["rowIndex"];
+    var section = e["section"];
+    if (e.rowExpansion && rowData) {
+        // render
+        var cell = section.stretchCell(0, rowIndex, true);
+        cell.setStyle("backgroundColor", "#cc7755");
+        section.setRowHeight(rowIndex, 72); // Customized height
+
+        var expContent = cell.getContent();
+        if (!expContent || !expContent._myExpansion) {
+            expContent = document.createElement("div");
+            expContent._myExpansion = true;
+
+            var firstLine = expContent._firstLine = document.createElement("div");
+            var secondLine = expContent._secondLine = document.createElement("div");
+            var loader = expContent._loader = document.createElement("ef-loader");
+            var button = document.createElement("button");
+            button.textContent = "Column & Row Index";
+            button.addEventListener("click", function (e) {
+                var pos = grid.api.getRelativePosition(e);
+                alert(pos.colIndex + ", " + pos.rowIndex);
+            });
+
+            secondLine.appendChild(button);
+
+            expContent.appendChild(firstLine);
+            expContent.appendChild(secondLine);
+            expContent.appendChild(loader);
+        }
+
+        var rowData = e.originalRowData;
+        if (rowData["My_Expansion_Status"] === "loading") {
+            expContent._firstLine.style.display = "none";
+            expContent._secondLine.style.display = "none";
+            expContent._loader.style.display = "";
+        } else {
+            expContent._firstLine.style.display = "";
+            expContent._secondLine.style.display = "";
+            expContent._loader.style.display = "none";
+        }
+        cell.setContent(expContent);
+    } else {
+        // dispose
+        var cell = section.stretchCell(0, rowIndex, false);
+        cell.setStyle("backgroundColor", "");
+        section.setRowHeight(rowIndex, section.getDefaultRowHeight()); // Default height
+    }
+}
+
+var onCellCliked = function(e) {
+    var pos = grid.api.getRelativePosition(e);
+    if (pos.sectionType === "content") { // Prevent clicking on header section
+        var rowIndex = pos.rowIndex;
+        var rowDef = grid.api.getRowDefinition(rowIndex);
+        if (rowDef) { // Prevent clicking on expanded row
+            var rowId = rowDef.getRowId();
+            var dv = grid.api.getDataView();
+            if (!dv.isRowExpansion(rowId)) {
+                if (rowDef.getData("My_Expansion_Status") == null) {
+                    rowDef.setData("My_Expansion_Status", "loading");
+                    // Simulate delay from data request
+                    setTimeout(onServerResponse.bind(null, dv, rowDef), 3000); // Asynchronous
+                }
+                dv.toggleRowExpansion(pos.rowIndex);
+            }
+        }
+    }
+};
+var onServerResponse = function(dv, rowDef) {
+    if (!dv.isRowExpansion(rowDef.getRowId())) {
+        rowDef.setData("My_Expansion_Status", "data received");
+    }
+    grid.api.getCoreGrid().requestRowRefresh(); // WORKAROUND: Force re-rendering
+};
+
+var configObj = {
+    columnReorder: true,
+    sorting: {
+        sortableColumns: true
+    },
+    columns: [
+        {name: "Company", field: fields[0]},
+        {name: "Market", field: fields[1], width: 120},
+        {name: "Last", field: fields[2], width: 100},
+        {name: "Net. Chng", field: fields[3], width: 100},
+        {name: "Industry", field: fields[4]}
+    ],
+    rowExpansionBinding: onRowExpansionBinding,
+    staticDataRows: records
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+grid.addEventListener("click", onCellCliked);
 
\ No newline at end of file diff --git a/template-125.html b/template-125.html index ad73a0e1..47400a7c 100644 --- a/template-125.html +++ b/template-125.html @@ -1,45 +1,32 @@ -

Row - Row Height

-

The height of content rows can be adjusted using the rowHeight property. Since Grid uses a row virtualization rendering technique, all of the rows must have the same height by default.

-
efx-grid {
-    height: 200px;
+

Row Grouping

+
+

Note: Built-in row grouping is deprecated in favor of the Row Grouping Extension. In terms of both functionalities and UIs, the extension provides more control and flexibility over the current APIs.

+
+

Row grouping can be done by using the Row Grouping Extension. To do the grouping, you will need to provide grouping criteria to the groupBy property of the rowGrouping option in the grid configuration object.

+
var configObj = {
+    ...
+    rowGrouping: {
+        groupBy: ["field1", "criteria"],
+    },
+    ...
 }
 
-
<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var records = DataGenerator.generateRecords(fields, { numRows: 6 });
-var configObj = {
-    rowHeight: 60,
-    columns: [
-        {name: "Company", field: fields[0]},
-        {name: "Market", field: fields[1], width: 100},
-        {name: "Last", field: fields[2], width: 80},
-        {name: "Net. Chng", field: fields[3], width: 80},
-        {name: "Industry", field: fields[4]}
-    ],
-    staticDataRows: records
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-

Variable row height

-

If you want to wrap long text content in the grid's cell, use the Content Wrap Extension. The extension will wrap text content that exceeds the cell width, making Grid act as if it is a native table.

-

However, text wrapping is resource-intensive, so it is turned off by default. To specify the column to be wrapped, set contentWrap to true in the column configuration.

-
efx-grid {
-    height: 200px;
+

Example

+
efx-grid {
+    height: 320px;
 }
 
-
<efx-grid id="grid"></efx-grid>
+
<big>Group By:</big>
+<button id="g1_btn">Market</button>
+<button id="g2_btn">Industry</button>
+<button id="g23_btn">Market and Industry</button>
+<button id="clear_btn">Reset Grouping</button>
+<br><br>
+<big>Expand:</big>
+<button id="expand_btn">Expand All Groups</button>
+<button id="collapse_btn">Collapse All Groups</button>
+<br><br>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -50,23 +37,51 @@ 

Row - Row Height

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 6 }); -var configObj = { - columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80}, - {name: "Net. Chng", field: fields[3], width: 80}, - {name: "Industry", field: fields[4], width: 100, contentWrap: true} - ], - staticDataRows: records, - extensions: [ - new ContentWrap() - ] -}; +var rowGroupingExt = new RowGrouping(); + var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; + var records = DataGenerator.generateRecords(fields, { numRows: 100 }); + var configObj = { + rowGrouping: { + groupBy: ["market", "industry"], + headerBinding: function(e) { + e.cell.setContent(e.groupId + " (" + e.dataSource.getAllRowIds().length + ")"); + }, + groupSortLogic: function(a, b) { // Optional + return (a < b ? -1 : ( a > b ? 1 : 0)); + }, + headerSpanning: true // Optional + }, + columns: [ + {name: "Company", field: fields[0]}, + {name: "Market", field: fields[1], width: 100}, + {name: "Last", field: fields[2], width: 80}, + {name: "Net. Chng", field: fields[3], width: 80}, + {name: "Industry", field: fields[4]} + ], + staticDataRows: records, + extensions: [rowGroupingExt] + }; + + var grid = document.getElementById("grid"); + grid.config = configObj; -var grid = document.getElementById("grid"); -grid.config = configObj; + g1_btn.addEventListener("click", function(e) { + rowGroupingExt.groupBy(fields[1]); + }); + g2_btn.addEventListener("click", function(e) { + rowGroupingExt.groupBy(fields[4]); + }); + g23_btn.addEventListener("click", function(e) { + rowGroupingExt.groupBy([fields[1], fields[4]]); + }); + clear_btn.addEventListener("click", function(e) { + rowGroupingExt.groupBy(null); + }); + expand_btn.addEventListener("click", function(e) { + rowGroupingExt.expandAll(); + }); + collapse_btn.addEventListener("click", function(e) { + rowGroupingExt.collapseAll(); + });
\ No newline at end of file diff --git a/template-126.html b/template-126.html index bc5fe22c..ad73a0e1 100644 --- a/template-126.html +++ b/template-126.html @@ -1,17 +1,10 @@ -

Row - Highlight and Selection

-

Row highlighting can be turned on/off by setting the options for rowHighlighting to true and false respectively. Row highlighting will be turn on by default.

-

All related row selection functionalities can be added through the Row Selection Extension.

-

Example

-
efx-grid {
+

Row - Row Height

+

The height of content rows can be adjusted using the rowHeight property. Since Grid uses a row virtualization rendering technique, all of the rows must have the same height by default.

+
efx-grid {
     height: 200px;
 }
-html hr {
-    margin: 5px;
-}
 
-
<big>Hover mouse over Grid to see row highlighting</big>
-<hr>
-<efx-grid id="grid"></efx-grid>
+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -25,7 +18,7 @@ 

Example

var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { numRows: 6 }); var configObj = { - rowHighlighting: true, // Add This Property to turn on/off + rowHeight: 60, columns: [ {name: "Company", field: fields[0]}, {name: "Market", field: fields[1], width: 100}, @@ -36,6 +29,43 @@

Example

staticDataRows: records }; +var grid = document.getElementById("grid"); +grid.config = configObj; +
+

Variable row height

+

If you want to wrap long text content in the grid's cell, use the Content Wrap Extension. The extension will wrap text content that exceeds the cell width, making Grid act as if it is a native table.

+

However, text wrapping is resource-intensive, so it is turned off by default. To specify the column to be wrapped, set contentWrap to true in the column configuration.

+
efx-grid {
+    height: 200px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { numRows: 6 });
+var configObj = {
+    columns: [
+        {name: "Company", field: fields[0]},
+        {name: "Market", field: fields[1], width: 100},
+        {name: "Last", field: fields[2], width: 80},
+        {name: "Net. Chng", field: fields[3], width: 80},
+        {name: "Industry", field: fields[4], width: 100, contentWrap: true}
+    ],
+    staticDataRows: records,
+    extensions: [
+        new ContentWrap()
+    ]
+};
+
 var grid = document.getElementById("grid");
 grid.config = configObj;
 
diff --git a/template-127.html b/template-127.html index 5fdd20a7..bc5fe22c 100644 --- a/template-127.html +++ b/template-127.html @@ -1,11 +1,17 @@ -

Row - Reordering

-

To allow the user to drag and reorder selected rows, add Row Dragging Extension instance to extensions property. The visual content of the dragged row can be rendered using the renderer function provided in the property dragBoxRenderer of the rowDragging option object. For more details, see Row Dragging Extension.

+

Row - Highlight and Selection

+

Row highlighting can be turned on/off by setting the options for rowHighlighting to true and false respectively. Row highlighting will be turn on by default.

+

All related row selection functionalities can be added through the Row Selection Extension.

Example

-
efx-grid {
+
efx-grid {
     height: 200px;
 }
+html hr {
+    margin: 5px;
+}
 
-
<efx-grid id="grid"></efx-grid>
+
<big>Hover mouse over Grid to see row highlighting</big>
+<hr>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -19,11 +25,7 @@ 

Example

var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { numRows: 6 }); var configObj = { - rowDragging: { - dragBoxRenderer: function(e) { - e.dragBox.textContent = e.dataRow[fields[0]]; - } - }, + rowHighlighting: true, // Add This Property to turn on/off columns: [ {name: "Company", field: fields[0]}, {name: "Market", field: fields[1], width: 100}, @@ -31,8 +33,7 @@

Example

{name: "Net. Chng", field: fields[3], width: 80}, {name: "Industry", field: fields[4]} ], - staticDataRows: records, - extensions: [ new RowDragging() ] + staticDataRows: records }; var grid = document.getElementById("grid"); diff --git a/template-128.html b/template-128.html index 46ecc30b..5fdd20a7 100644 --- a/template-128.html +++ b/template-128.html @@ -1,22 +1,11 @@ -

Row - Show/Hide

-

Content rows can be hidden and shown based on their row ID, and an additional API unhides all currently hidden rows.

-
-

Note: In most cases, the row ID is not equivalent to the row index. It can, however, be retrieved if you know the index (refer to the JavaScript section in the demo).

-
-

Both the showRows() and hideRows() APIs accept either an individual value (string or integer) or an array of values. This kind of state is independent of the programmatic filtering of content, and will correctly reclassify hidden rows on sorting/grouping.

+

Row - Reordering

+

To allow the user to drag and reorder selected rows, add Row Dragging Extension instance to extensions property. The visual content of the dragged row can be rendered using the renderer function provided in the property dragBoxRenderer of the rowDragging option object. For more details, see Row Dragging Extension.

Example

-
html hr {
-    margin: 5px;
-}
-efx-grid {
+
efx-grid {
     height: 200px;
 }
 
-
<button id="hide_btn">Hide top 3 rows</button>
-<button id="show_btn">Show last 2 hidden rows</button>
-<button id="clear_btn">Unhide all</button>
-<hr>
-<efx-grid id="grid"></efx-grid>
+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -27,38 +16,26 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["id", "companyName", "market", "CF_LAST", "CF_NETCHNG"]; -var records = DataGenerator.generateRecords(fields, { numRows: 20 }); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { numRows: 6 }); var configObj = { + rowDragging: { + dragBoxRenderer: function(e) { + e.dragBox.textContent = e.dataRow[fields[0]]; + } + }, columns: [ - {name: "Id", field: fields[0], width: 50}, - {name: "Company", field: fields[1]}, - {name: "Market", field: fields[2], width: 100}, - {name: "Last", field: fields[3], width: 80}, - {name: "Net. Chng", field: fields[4], width: 80}, + {name: "Company", field: fields[0]}, + {name: "Market", field: fields[1], width: 100}, + {name: "Last", field: fields[2], width: 80}, + {name: "Net. Chng", field: fields[3], width: 80}, + {name: "Industry", field: fields[4]} ], - staticDataRows: records + staticDataRows: records, + extensions: [ new RowDragging() ] }; var grid = document.getElementById("grid"); grid.config = configObj; -var rowId1, rowId2, rowId3; -document.getElementById("hide_btn").addEventListener("click", function() { - // Hide rows at index 0 and 1 (rowIds are "0" and "1" respectively since rows haven"t been sorted/filtered) - var dataView = grid.api.getDataView(); - rowId1 = dataView.getRowId(0); - rowId2 = dataView.getRowId(1) - rowId3 = dataView.getRowId(2) - grid.api.hideRows([rowId1, rowId2, rowId3]); -}); - -document.getElementById("show_btn").addEventListener("click", function() { - grid.api.showRows([rowId2, rowId3]); -}); - -document.getElementById("clear_btn").addEventListener("click", function() { - // Unhide all currently hidden rows - grid.api.unhideAllRows(); -});
\ No newline at end of file diff --git a/template-129.html b/template-129.html index bf8cb823..46ecc30b 100644 --- a/template-129.html +++ b/template-129.html @@ -1,19 +1,21 @@ -

Horizontal Scrollbar

-

By default, Grid behaves like a native div element that has CSS "display: block;". So, Grid has a default size of 100% of the parent width.

-

Grid's default column widths have no fixed size. The column size will be divided equally on the available space. And Grid columns will fit within the available space. So, Grid will never show a horizontal scrollbar by default, as the content (column) width does not exceed its container (grid element) width.

-

If you want to enable the horizontal scrollbar, two conditions must be met:

-
    -
  1. All of the grid columns must have a fixed size.
  2. -
  3. The total column width must exceed the grid width.
  4. -
+

Row - Show/Hide

+

Content rows can be hidden and shown based on their row ID, and an additional API unhides all currently hidden rows.

-

Note: once Grid's horizontal scrollbar is shown, column virtualization will be activated as well.

+

Note: In most cases, the row ID is not equivalent to the row index. It can, however, be retrieved if you know the index (refer to the JavaScript section in the demo).

+

Both the showRows() and hideRows() APIs accept either an individual value (string or integer) or an array of values. This kind of state is independent of the programmatic filtering of content, and will correctly reclassify hidden rows on sorting/grouping.

Example

-
<button id="reset_btn">Reset All Column Widths to Default</button>
-<button id="fixate_all_btn">Fixate All Column Widths</button>
-<button id="fixate_first_btn">Fixate the First Column</button>
-<br><br>
+
html hr {
+    margin: 5px;
+}
+efx-grid {
+    height: 200px;
+}
+
+
<button id="hide_btn">Hide top 3 rows</button>
+<button id="show_btn">Show last 2 hidden rows</button>
+<button id="clear_btn">Unhide all</button>
+<hr>
 <efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
@@ -25,65 +27,38 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 6 }); +var fields = ["id", "companyName", "market", "CF_LAST", "CF_NETCHNG"]; +var records = DataGenerator.generateRecords(fields, { numRows: 20 }); var configObj = { columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1]}, - {name: "Last", field: fields[2]}, - {name: "Net. Chng", field: fields[3]}, - {name: "Industry", field: fields[4]} + {name: "Id", field: fields[0], width: 50}, + {name: "Company", field: fields[1]}, + {name: "Market", field: fields[2], width: 100}, + {name: "Last", field: fields[3], width: 80}, + {name: "Net. Chng", field: fields[4], width: 80}, ], staticDataRows: records }; var grid = document.getElementById("grid"); grid.config = configObj; - -document.getElementById("reset_btn").addEventListener("click", function(e) { - grid.api.getCoreGrid().setColumnWidths([1, 1, 1, 1, 1], true); // All columns will have equal width -}); -document.getElementById("fixate_all_btn").addEventListener("click", function(e) { - grid.api.getCoreGrid().setColumnWidths([300, 150, 150, 150, 200], false); // Set all column widths to the specified size. +var rowId1, rowId2, rowId3; +document.getElementById("hide_btn").addEventListener("click", function() { + // Hide rows at index 0 and 1 (rowIds are "0" and "1" respectively since rows haven"t been sorted/filtered) + var dataView = grid.api.getDataView(); + rowId1 = dataView.getRowId(0); + rowId2 = dataView.getRowId(1) + rowId3 = dataView.getRowId(2) + grid.api.hideRows([rowId1, rowId2, rowId3]); }); -document.getElementById("fixate_first_btn").addEventListener("click", function(e) { - var core = grid.api.getCoreGrid(); - core.setColumnWidth(0, 200); // Set the first column to have fixed width (200px); - core.setColumnWidths([null, 1, 1, 1, 3], true); // Set the last four columns to have no size -}); -
-

Non-overlap horizontal scrollbar

-

The Grid horizontal scrollbar, by default, is shown on top of the grid. This is to avoid the content jittering when the layout is changed. However, in some cases, the horizontal scrollbar may hinder or prevent interaction with the content, especially for the bottommost row. Use the contentBottomPadding flag to reserve some space on the bottom to stop this from happening.

-

autoHideScrollbar can also be used to stop automatic scrollbar hiding.

-

Example

-
<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
 
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var records = DataGenerator.generateRecords(fields, { numRows: 10 });
-var configObj = {
-    autoHideScrollbar: false,
-    contentBottomPadding: 9,
-    columns: [
-        {name: "Company", field: fields[0], width: 300},
-        {name: "Market", field: fields[1], width: 150},
-        {name: "Last", field: fields[2], width: 150},
-        {name: "Net. Chng", field: fields[3], width: 150},
-        {name: "Industry", field: fields[4], width: 200}
-    ],
-    staticDataRows: records
-};
+document.getElementById("show_btn").addEventListener("click", function() {
+        grid.api.showRows([rowId2, rowId3]);
+});
 
-var grid = document.getElementById("grid");
-grid.config = configObj;
+document.getElementById("clear_btn").addEventListener("click", function() {
+        // Unhide all currently hidden rows
+        grid.api.unhideAllRows();
+});
 
\ No newline at end of file diff --git a/template-130.html b/template-130.html index feba204e..2fd75808 100644 --- a/template-130.html +++ b/template-130.html @@ -1,9 +1,18 @@ -

Left Side Column Pinning/Freezing

-

Sometimes Grid can contain a large number of columns and when scrolled to the right, without the row header, users might lose track of what kind of data is in the row. -To solve this, you can freeze or pin columns on the left side to act like a row indicator. To do this, set the leftPinned property to true on the column configuration object for the column you want to be frozen/pinned.

-

Similarly, rightPinned property can be used to pin the columns on the right side.

-

Example

-
<efx-grid id="grid"></efx-grid>
+

Horizontal Scrollbar

+

By default, Grid behaves like a native div element that has CSS "display: block;". So, Grid has a default size of 100% of the parent width.

+

Grid's default column widths have no fixed size. The column size will be divided equally on the available space. And Grid columns will fit within the available space. So, Grid will never show a horizontal scrollbar by default, as the content (column) width does not exceed its container (grid element) width.

+

If you want to enable the horizontal scrollbar, two conditions must be met:

+
    +
  1. All of the grid columns must have a fixed size.
  2. +
  3. The total column width must exceed the grid width.
  4. +
+

Sizing column example

+
<button id="reset_btn">Reset all column widths to default</button>
+<button id="fixate_all_btn">Fixate all column widths</button>
+<button id="fixate_first_btn">Fixate the first column</button>
+<br><br>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -15,36 +24,37 @@ 

Example

Please see the document for further information. ---------------------------------------------------------------------------*/ var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); +var records = DataGenerator.generateRecords(fields, { numRows: 6 }); var configObj = { columns: [ - {name: " ", width: 24}, - {name: "Company", field: fields[0], width: 250, leftPinned: true }, - {name: "Market", field: fields[1], width: 150}, - {name: "Last", field: fields[2], width: 150}, - {name: "Net. Chng", field: fields[3], width: 150}, - {name: "Industry", field: fields[4], width: 300} + {name: "Company", field: fields[0]}, + {name: "Market", field: fields[1]}, + {name: "Last", field: fields[2]}, + {name: "Net. Chng", field: fields[3]}, + {name: "Industry", field: fields[4]} ], staticDataRows: records }; var grid = document.getElementById("grid"); grid.config = configObj; + +document.getElementById("reset_btn").addEventListener("click", function(e) { + grid.api.getCoreGrid().setColumnWidths([1, 1, 1, 1, 1], true); // All columns will have equal width +}); +document.getElementById("fixate_all_btn").addEventListener("click", function(e) { + grid.api.getCoreGrid().setColumnWidths([300, 150, 150, 150, 200], false); // Set all column widths to the specified size. +}); +document.getElementById("fixate_first_btn").addEventListener("click", function(e) { + var core = grid.api.getCoreGrid(); + core.setColumnWidth(0, 200); // Set the first column to have fixed width (200px); + core.setColumnWidths([null, 1, 1, 1, 3], true); // Set the last four columns to have no size +});
-

Pinning column at runtime

-

Pinning column at runtime can be done through pinColumn method from Grid's API. The pinned column will be move to the right most of frozen area. To unpin a column, call unpinColumn. The unpinned column will be moved to the left most of unfrozen area.

-

Example

-
html hr, button {
-    margin: 5px;
-}
-
-
<fieldset id="pinning_set">
-    <legend>Pinning</legend>
-</fieldset>
-<fieldset id="unpinning_set">
-    <legend>Unpinning</legend>
-</fieldset>
-<efx-grid id="grid"></efx-grid>
+

Non-overlap horizontal scrollbar example

+

The Grid horizontal scrollbar, by default, is shown on top of the grid. This is to avoid the content jittering when the layout is changed. However, in some cases, the horizontal scrollbar may hinder or prevent interaction with the content, especially for the bottommost row. Use the contentBottomPadding flag to reserve some space on the bottom to stop this from happening.

+

autoHideScrollbar can also be used to stop automatic scrollbar hiding.

+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -55,42 +65,17 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "Column 6", "Column 7"]; +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { numRows: 10 }); - -var onClickPinning = function(e) { - var btn = e.currentTarget; - grid.api.pinColumn(btn.colIndex); -}; -var onClickUnpinning = function(e) { - var btn = e.currentTarget; - grid.api.unpinColumn(btn.colIndex); -}; - -var len = fields.length; -for(var i = 0; i < 4; ++i) { - var btn = document.createElement("button"); - btn.colIndex = i; - btn.addEventListener("click", onClickPinning); - btn.textContent = "Column " + (i + 1); - pinning_set.appendChild(btn); - - btn = document.createElement("button"); - btn.colIndex = i; - btn.addEventListener("click", onClickUnpinning); - btn.textContent = "Column " + (i + 1); - unpinning_set.appendChild(btn); -} - var configObj = { + autoHideScrollbar: false, + contentBottomPadding: 9, columns: [ - {name: "Company", field: fields[0], width: 250}, + {name: "Company", field: fields[0], width: 300}, {name: "Market", field: fields[1], width: 150}, {name: "Last", field: fields[2], width: 150}, {name: "Net. Chng", field: fields[3], width: 150}, - {name: "Industry", field: fields[4], width: 200}, - {field: fields[5], width: 150}, - {field: fields[6], width: 150} + {name: "Industry", field: fields[4], width: 200} ], staticDataRows: records }; @@ -98,4 +83,6 @@

Example

var grid = document.getElementById("grid"); grid.config = configObj;
-




+
+
+
\ No newline at end of file diff --git a/template-131.html b/template-131.html index f6497a9b..feba204e 100644 --- a/template-131.html +++ b/template-131.html @@ -1,11 +1,9 @@ -

Non-overlap Scrollbars

-

Normally, Grid's scrollbars are shown on top of its content. This behavior can result in scrollbars blocking the display and interaction of the content. You can work around this issue by adding extra content to allow space for the scrollbars. To do this set contentRightPadding and contentBottomPadding properties in the configuration, as shown in the example below.

-

Content padding example

-
efx-grid {
-    height: 200px;
-}
-
-
<efx-grid id="grid"></efx-grid>
+

Left Side Column Pinning/Freezing

+

Sometimes Grid can contain a large number of columns and when scrolled to the right, without the row header, users might lose track of what kind of data is in the row. +To solve this, you can freeze or pin columns on the left side to act like a row indicator. To do this, set the leftPinned property to true on the column configuration object for the column you want to be frozen/pinned.

+

Similarly, rightPinned property can be used to pin the columns on the right side.

+

Example

+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -17,13 +15,11 @@ 

Content padding example

Please see the document for further information. ---------------------------------------------------------------------------*/ var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 20 }); +var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { - contentRightPadding: 14, - contentBottomPadding: 14, - autoHideScrollbar: false, columns: [ - {name: "Company", field: fields[0], width: 250}, + {name: " ", width: 24}, + {name: "Company", field: fields[0], width: 250, leftPinned: true }, {name: "Market", field: fields[1], width: 150}, {name: "Last", field: fields[2], width: 150}, {name: "Net. Chng", field: fields[3], width: 150}, @@ -35,24 +31,20 @@

Content padding example

var grid = document.getElementById("grid"); grid.config = configObj;
-

This extra content may not be desirable though, as it can add to the amount of scroll distance and not actually reserve space for the scrollbars. Instead, you can change the parent of the scrollbars and reserve some space using CSS paddings. To change the parent of the scrollbars supply the parent element to the scrollbarParent property in the configuration object, as shown below.

-
-

Note: autoHideScrollbar is turned off by default if scrollbarParent is supplied.

-
-

Changing the scrollbar parent example

-
#grid_container {
-    height: 200px; 
-    padding-right: 14px;
-    padding-bottom: 14px;
-    box-sizing: border-box;
-}
-efx-grid {
-    height: 100%;
+

Pinning column at runtime

+

Pinning column at runtime can be done through pinColumn method from Grid's API. The pinned column will be move to the right most of frozen area. To unpin a column, call unpinColumn. The unpinned column will be moved to the left most of unfrozen area.

+

Example

+
html hr, button {
+    margin: 5px;
 }
 
-
<div id="grid_container">
-    <efx-grid id="grid"></efx-grid>
-</div>
+
<fieldset id="pinning_set">
+    <legend>Pinning</legend>
+</fieldset>
+<fieldset id="unpinning_set">
+    <legend>Unpinning</legend>
+</fieldset>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -63,16 +55,42 @@ 

Changing the scrollbar parent exa Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 20 }); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "Column 6", "Column 7"]; +var records = DataGenerator.generateRecords(fields, { numRows: 10 }); + +var onClickPinning = function(e) { + var btn = e.currentTarget; + grid.api.pinColumn(btn.colIndex); +}; +var onClickUnpinning = function(e) { + var btn = e.currentTarget; + grid.api.unpinColumn(btn.colIndex); +}; + +var len = fields.length; +for(var i = 0; i < 4; ++i) { + var btn = document.createElement("button"); + btn.colIndex = i; + btn.addEventListener("click", onClickPinning); + btn.textContent = "Column " + (i + 1); + pinning_set.appendChild(btn); + + btn = document.createElement("button"); + btn.colIndex = i; + btn.addEventListener("click", onClickUnpinning); + btn.textContent = "Column " + (i + 1); + unpinning_set.appendChild(btn); +} + var configObj = { - scrollbarParent: document.getElementById("grid_container"), columns: [ {name: "Company", field: fields[0], width: 250}, {name: "Market", field: fields[1], width: 150}, {name: "Last", field: fields[2], width: 150}, {name: "Net. Chng", field: fields[3], width: 150}, - {name: "Industry", field: fields[4], width: 300} + {name: "Industry", field: fields[4], width: 200}, + {field: fields[5], width: 150}, + {field: fields[6], width: 150} ], staticDataRows: records }; @@ -80,4 +98,4 @@

Changing the scrollbar parent exa var grid = document.getElementById("grid"); grid.config = configObj;

- \ No newline at end of file +




diff --git a/template-132.html b/template-132.html index 2c755feb..f6497a9b 100644 --- a/template-132.html +++ b/template-132.html @@ -1,7 +1,7 @@ -

Right Side Column Pinning/Freezing

-

When Grid contains controls or buttons on the right side you should freeze or pin these columns, as they should not be part of the scrollable content. To do this use the rightPinned property on the column configuration object.

-

Example

-
efx-grid {
+

Non-overlap Scrollbars

+

Normally, Grid's scrollbars are shown on top of its content. This behavior can result in scrollbars blocking the display and interaction of the content. You can work around this issue by adding extra content to allow space for the scrollbars. To do this set contentRightPadding and contentBottomPadding properties in the configuration, as shown in the example below.

+

Content padding example

+
efx-grid {
     height: 200px;
 }
 
@@ -16,28 +16,63 @@

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var buttonFormatter = function(e) { - var cell = e.cell; - var btn = cell.getContent(); - if(!btn) { - btn = document.createElement("button"); - } - btn.textContent = e.data; - cell.setContent(btn); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { numRows: 20 }); +var configObj = { + contentRightPadding: 14, + contentBottomPadding: 14, + autoHideScrollbar: false, + columns: [ + {name: "Company", field: fields[0], width: 250}, + {name: "Market", field: fields[1], width: 150}, + {name: "Last", field: fields[2], width: 150}, + {name: "Net. Chng", field: fields[3], width: 150}, + {name: "Industry", field: fields[4], width: 300} + ], + staticDataRows: records }; -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "id"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); +var grid = document.getElementById("grid"); +grid.config = configObj; +
+

This extra content may not be desirable though, as it can add to the amount of scroll distance and not actually reserve space for the scrollbars. Instead, you can change the parent of the scrollbars and reserve some space using CSS paddings. To change the parent of the scrollbars supply the parent element to the scrollbarParent property in the configuration object, as shown below.

+
+

Note: autoHideScrollbar is turned off by default if scrollbarParent is supplied.

+
+

Changing the scrollbar parent example

+
#grid_container {
+    height: 200px; 
+    padding-right: 14px;
+    padding-bottom: 14px;
+    box-sizing: border-box;
+}
+efx-grid {
+    height: 100%;
+}
+
+
<div id="grid_container">
+    <efx-grid id="grid"></efx-grid>
+</div>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { numRows: 20 });
 var configObj = {
+    scrollbarParent: document.getElementById("grid_container"),
     columns: [
         {name: "Company", field: fields[0], width: 250},
-        {name: "Market", field: fields[1], width: 100},
-        {name: "Last", field: fields[2], width: 100},
-        {name: "Net. Chng", field: fields[3], width: 100},
-        {name: "Industry", field: fields[4], width: 300},
-        {name: "Op.1", field: fields[5], width: 60, rightPinned: true, binding: buttonFormatter, alignment: "center"},
-        {name: "Op.2", field: fields[5], width: 60, rightPinned: true, binding: buttonFormatter, alignment: "center"},
-        {name: "Op.3", field: fields[5], width: 60, rightPinned: true, binding: buttonFormatter, alignment: "center"}
+        {name: "Market", field: fields[1], width: 150},
+        {name: "Last", field: fields[2], width: 150},
+        {name: "Net. Chng", field: fields[3], width: 150},
+        {name: "Industry", field: fields[4], width: 300}
     ],
     staticDataRows: records
 };
diff --git a/template-133.html b/template-133.html
index 5e7d1371..2c755feb 100644
--- a/template-133.html
+++ b/template-133.html
@@ -1,9 +1,8 @@
-

Scroll Speed

-

Generally, Grid will contain a large number of rows. Grid elements could block page scrolling due to slow native wheel scrolling speed and long scroll distance. So, by default, Grid's wheel scroll speed will increase exponentially once the content height exceeds a certain threshold. This behavior may not be wanted, so to return to the native wheel default behavior enable linearWheelScrolling.

-

You can also force scrolling to move for the whole row by using the stepScroll property.

+

Right Side Column Pinning/Freezing

+

When Grid contains controls or buttons on the right side you should freeze or pin these columns, as they should not be part of the scrollable content. To do this use the rightPinned property on the column configuration object.

Example

-
efx-grid {
-    height: 400px;
+
efx-grid {
+    height: 200px;
 }
 
<efx-grid id="grid"></efx-grid>
@@ -17,18 +16,28 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ +var buttonFormatter = function(e) { + var cell = e.cell; + var btn = cell.getContent(); + if(!btn) { + btn = document.createElement("button"); + } + btn.textContent = e.data; + cell.setContent(btn); +}; + var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "id"]; -var records = DataGenerator.generateRecords(fields, { numRows: 1000 }); +var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { - linearWheelScrolling: true, - stepScroll: true, columns: [ - {name: "ID", field: fields[5], width: 40}, - {name: "Company", field: fields[0]}, + {name: "Company", field: fields[0], width: 250}, {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80}, - {name: "Net. Chng", field: fields[3], width: 80}, - {name: "Industry", field: fields[4]} + {name: "Last", field: fields[2], width: 100}, + {name: "Net. Chng", field: fields[3], width: 100}, + {name: "Industry", field: fields[4], width: 300}, + {name: "Op.1", field: fields[5], width: 60, rightPinned: true, binding: buttonFormatter, alignment: "center"}, + {name: "Op.2", field: fields[5], width: 60, rightPinned: true, binding: buttonFormatter, alignment: "center"}, + {name: "Op.3", field: fields[5], width: 60, rightPinned: true, binding: buttonFormatter, alignment: "center"} ], staticDataRows: records }; diff --git a/template-134.html b/template-134.html index 4877f0ee..5e7d1371 100644 --- a/template-134.html +++ b/template-134.html @@ -1,9 +1,9 @@ -

Scrollbar Visibility

-

Instead of fading in or out on hover (default behavior), Grid scrollbars can be set to always be visible whenever the content is scrollable.

-

This behavior can be enabled upon grid initialization using the autoHideScrollbar option. The values can be false for always-on, and true for fade in/out (default).

+

Scroll Speed

+

Generally, Grid will contain a large number of rows. Grid elements could block page scrolling due to slow native wheel scrolling speed and long scroll distance. So, by default, Grid's wheel scroll speed will increase exponentially once the content height exceeds a certain threshold. This behavior may not be wanted, so to return to the native wheel default behavior enable linearWheelScrolling.

+

You can also force scrolling to move for the whole row by using the stepScroll property.

Example

-
efx-grid {
-    height: 200px;
+
efx-grid {
+    height: 400px;
 }
 
<efx-grid id="grid"></efx-grid>
@@ -17,16 +17,18 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "id"]; +var records = DataGenerator.generateRecords(fields, { numRows: 1000 }); var configObj = { - autoHideScrollbar: false, + linearWheelScrolling: true, + stepScroll: true, columns: [ - {name: "Company", field: fields[0], width: 250}, - {name: "Market", field: fields[1], width: 150}, - {name: "Last", field: fields[2], width: 150}, - {name: "Net. Chng", field: fields[3], width: 150}, - {name: "Industry", field: fields[4], width: 300} + {name: "ID", field: fields[5], width: 40}, + {name: "Company", field: fields[0]}, + {name: "Market", field: fields[1], width: 100}, + {name: "Last", field: fields[2], width: 80}, + {name: "Net. Chng", field: fields[3], width: 80}, + {name: "Industry", field: fields[4]} ], staticDataRows: records }; diff --git a/template-135.html b/template-135.html index fc58fc2b..4877f0ee 100644 --- a/template-135.html +++ b/template-135.html @@ -1,64 +1,8 @@ -

Vertical Scrollbar

-

By default, Grid behaves like a native div element that has CSS "display: block;". This means Grid's height will be expanded as the number of its rows is increasing. In other words, it has a dynamic height equal to its content height. So Grid will never show a vertical scrollbar by default, as the content height does not exceed its container (grid element) height.

-

If you want to enable the vertical scrollbar, two conditions must be met:

-
    -
  1. Grid must have some specific height (for example, 200px, 50%, or 100%).
  2. -
  3. Grid content height must exceed the height specified in #1.
  4. -
-
-

Note: once Grid's vertical scrollbar is shown, Grid's row virtualization will also be activated. Not all elements will be created or rendered. The same cells will be shared across multiple rows.

-

Also, if the containers or Grid styles have been changed by JavaScript, you need to notify Grid about the change in order to update the layout. Use getCoreGrid().updateLayout() to force updating the layout.

-
+

Scrollbar Visibility

+

Instead of fading in or out on hover (default behavior), Grid scrollbars can be set to always be visible whenever the content is scrollable.

+

This behavior can be enabled upon grid initialization using the autoHideScrollbar option. The values can be false for always-on, and true for fade in/out (default).

Example

-
<button id="reset_btn">Reset Grid Height to Default</button>
-<button id="set_200_btn">Set Grid Height to 200px</button>
-<button id="set_600_btn">Set Grid Height to 600px</button>
-<br><br>
-<efx-grid id="grid" style="height: 200px"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var records = DataGenerator.generateRecords(fields, { numRows: 10 });
-var configObj = {
-    columns: [
-        {name: "Company", field: fields[0]},
-        {name: "Market", field: fields[1], width: 100},
-        {name: "Last", field: fields[2], width: 80},
-        {name: "Net. Chng", field: fields[3], width: 80},
-        {name: "Industry", field: fields[4]}
-    ],
-    staticDataRows: records
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-document.getElementById("reset_btn").addEventListener("click", function(e) {
-    grid.style.height = "";
-    grid.api.getCoreGrid().updateLayout(); // Notify grid that some CSS have been changed
-});
-document.getElementById("set_200_btn").addEventListener("click", function(e) {
-    grid.style.height = "200px";
-    grid.api.getCoreGrid().updateLayout(); // Notify grid that some CSS have been changed
-});
-document.getElementById("set_600_btn").addEventListener("click", function(e) {
-    grid.style.height = "600px";
-    grid.api.getCoreGrid().updateLayout(); // Notify grid that some CSS have been changed
-});
-
-

Non-overlap vertical scrollbar

-

The Grid vertical scrollbar, by default, is shown on top of the grid. This is to avoid jittering the content when the layout is changed. However, in some cases, the vertical scrollbar may hinder or prevent interaction with the content, especially for the rightmost column. Use the contentRightPadding flag to reserve some space on the right to prevent this from happening.

-

autoHideScrollbar could also be used to stop automatic scrollbar hiding.

-

Example

-
efx-grid {
+
efx-grid {
     height: 200px;
 }
 
@@ -77,13 +21,12 @@

Example

var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { autoHideScrollbar: false, - contentRightPadding: 14, columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80}, - {name: "Net. Chng", field: fields[3], width: 80}, - {name: "Industry", field: fields[4]} + {name: "Company", field: fields[0], width: 250}, + {name: "Market", field: fields[1], width: 150}, + {name: "Last", field: fields[2], width: 150}, + {name: "Net. Chng", field: fields[3], width: 150}, + {name: "Industry", field: fields[4], width: 300} ], staticDataRows: records }; diff --git a/template-136.html b/template-136.html index 1096ff56..6fdafae1 100644 --- a/template-136.html +++ b/template-136.html @@ -1,61 +1,90 @@ -

Showcase

-
body {
-    padding: 24px;
-}
+

Vertical Scrollbar

+

By default, Grid behaves like a native div element that has CSS "display: block;". This means Grid's height will be expanded as the number of its rows is increasing. In other words, it has a dynamic height equal to its content height. So Grid will never show a vertical scrollbar by default, as the content height does not exceed its container (grid element) height.

+

If you want to enable the vertical scrollbar, two conditions must be met:

+
    +
  1. Grid must have some specific height (for example, 200px, 50%, or 100%).
  2. +
  3. Grid content height must exceed the height specified in #1.
  4. +
+
+

Note: once Grid's vertical scrollbar is shown, Grid's row virtualization will also be activated. Not all elements will be created or rendered. The same cells will be shared across multiple rows.

+

Also, if the containers or Grid styles have been changed by JavaScript, you need to notify Grid about the change in order to update the layout. Use getCoreGrid().updateLayout() to force updating the layout.

+
+

Fixed height grid example

+

The below example shows how Grid's height affects vertical scrollbar's visibility:

+
<button id="reset_btn">Reset height to default</button>
+<button id="set_200_btn">Set height to 200px</button>
+<button id="set_600_btn">Set height to 600px</button>
+<br><br>
+<efx-grid id="grid" style="height: 200px"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
 
-efx-grid {
-    height: 600px;
-}
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { numRows: 15 });
+var configObj = {
+    columns: [
+        {name: "Company", field: fields[0]},
+        {name: "Market", field: fields[1], width: 100},
+        {name: "Last", field: fields[2], width: 80},
+        {name: "Net. Chng", field: fields[3], width: 80},
+        {name: "Industry", field: fields[4]}
+    ],
+    staticDataRows: records
+};
 
-#grouping .arrow {
-    color: red;
-    margin: 0 5px;
-    vertical-align: middle;
-}
+var grid = document.getElementById("grid");
+grid.config = configObj;
 
-#grouping .arrow:last-child {
-    display: none;
+document.getElementById("reset_btn").addEventListener("click", function(e) {
+    grid.style.height = "";
+    grid.api.getCoreGrid().updateLayout(); // Notify grid that some CSS have been changed
+});
+document.getElementById("set_200_btn").addEventListener("click", function(e) {
+    grid.style.height = "200px";
+    grid.api.getCoreGrid().updateLayout(); // Notify grid that some CSS have been changed
+});
+document.getElementById("set_600_btn").addEventListener("click", function(e) {
+    grid.style.height = "600px";
+    grid.api.getCoreGrid().updateLayout(); // Notify grid that some CSS have been changed
+});
+
+

Making Grid fill available space example

+

flex can be used to define Grid's height. By doing it this way, Grid's height will be changed when the window or its container size is changed.

+
body {
+    height: 500px; /* For illustrative purpose */
+    padding: 4px;
+    box-sizing: border-box;
 }
-
-ef-pill {
-    margin: auto;
+.flex-container {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
 }
-
-#column_grouping_selector {
-    margin-right: 5px;
+html hr {
+    margin: 5px;
 }
-
-hr {
-    margin: 8px;
+efx-grid {
+    flex: 1;
+    min-height: 0;
+    max-height: none;
+    outline: 1px solid blue; /* For illustrative purpose */
 }
 
-
<fieldset>
-    <legend>Operation</legend>
-    <span>
-        <ef-button id="select_column_btn">Select Columns</ef-button>
-        Data Size:
-        <ef-select id="dataSize">
-            <ef-item value="10">10 Rows</ef-item>
-            <ef-item value="100" selected>100 Rows</ef-item>
-            <ef-item value="1000">1,000 Rows</ef-item>
-            <ef-item value="10000">10,000 Rows</ef-item>
-            <ef-item value="100000">100,000 Rows</ef-item>
-        </ef-select>
-    </span>
-    <hr>
-    <span>
-        <label for="search_input">Filter: </label>
-        <input id="search_input" type="search" placeholder="Filter any column">
-    </span>
-    <hr>
-    <div id="grouping">
-        <ef-select id="column_grouping_selector" placeholder="Group By"></ef-select>
+
<div class="flex-container" style="height: 100%">
+    <div>
+        <button id="remove_btn">Remove top 5 rows</button>
     </div>
-</fieldset>
-<hr>
-
-<efx-grid id="preview"></efx-grid>
-<ef-overlay-menu id="popup_menu"></ef-overlay-menu>
+    <hr>
+    <efx-grid id="grid"></efx-grid>
+</div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -66,713 +95,63 @@ 

Showcase

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var checkboxExt = new Checkbox(); -var rowGroupingExt = new RowGrouping(); -var conditionalColoringExt = new ConditionalColoring(); -var columnGroupingExt = new ColumnGrouping(); -var cellSelectionExt = new CellSelection(); -var filterInputExt = new FilterInput(); -var columnResizingExt = new ColumnResizing(); -var textFormattingExt = new TextFormatting(); -var heatMapExt = new HeatMap(); -var inCellEditingExt = new InCellEditing(); -var percentBarExt = new PercentBar(); -var filterExt = new RowFiltering(); -var rowColoring = new RowColoring(); -var contextMenuExt = new ContextMenu(); -var columnFitterExt = new ColumnFitter(); -var columnStackExt = new ColumnStack(); -var rangeBarExt = new RangeBar(); -var generator = DataGenerator; -var dateTimePicker = tr.EmeraldDateTimePickerFormatter ? tr.EmeraldDateTimePickerFormatter : EFDateTimePickerFormatter; // WORKAROUND: for datetime picker in v6 - -var grid = window.grid = document.getElementsByTagName("efx-grid")[0]; -var dataSizeSelect = document.getElementById("dataSize"); -var selectColumnBtn = document.getElementById("select_column_btn"); - -var userList = [ - "Amanda Herrera", - "Josh Robertson", - "Abbie Parker", - "Christopher Washington", - "Casey Alvarez", - "Joshua Castillo", - "Skye Wilson", - "Tommy Medina", - "Vincent Smith", - "Jackson Garcia", - "Lisa Alexander", - "Holly Brooks", - "Zara Marshall", - "Kiera Shaw" -]; -const userListEntries = userList.map(function (item) { - return { - label: item, - value: item - }; -}); - -var codeList = { - "FRA": "France", - "GBR": "United Kingdom", - "ISL": "Iceland", - "ITA": "Italy", - "PRT": "Protugal", - "SWE": "Sweden", - "GRC": "Greece", - "DEU": "Germany", - "NOR": "Norway", - "IND": "India", - "CHN": "China" -}; - -var languageList = ["French", "English", "German", "Italian", "Portuguese", "Chinese"]; - -const languageEntries = languageList.map(function (item) { - return { - label: item, - value: item - }; -}); - -generator.addFieldInfo("userList", { - type: "set", - members: userList -}) - -generator.addFieldInfo("languageList", { - type: "set", - members: languageList -}); - -generator.addFieldInfo("countryList", { - type: "set", - members: ["FRA", "GBR", "ISL", "ITA", "PRT", "SWE", "GRC", "DEU", "NOR", "GBR", "IND", "FRA", "DEU", "CHN" - ] -}) - - -generator.addFieldInfo("CF_CLOSE", { - type: "number", - min: 0, - max: 1000, - prec: 2 -}); - -generator.addFieldInfo("TR.TSVWAP", { - type: "number", - min: 0, - max: 1000, - prec: 2 -}); - -generator.addFieldInfo("Jan", { - type: "number", - min: -100, - max: 100, - prec: 2 -}); - -generator.addFieldInfo("Feb", { - type: "number", - min: -100, - max: 100, - prec: 2 -}); - -generator.addFieldInfo("Mar", { - type: "number", - min: -100, - max: 100, - prec: 2 -}); - -generator.addFieldInfo("changed", { - type: "number", - min: -100, - max: 100, - prec: 2 -}); - -var dateConditions = [ - { - expression: ["GT", 60], - backgroundColor: "#b9f6ca66" - }, - { - expression: ["LT", 20], - backgroundColor: "#ff80ab66" - }, -]; - -var dataTypeFields = [ - "id", - "userList", - "languageList", - "countryList", - "boolean", // Bought - "TR.Volume", // Bank Balance - "changed", // Rating - "CFLOW", - "CF_LAST", - "CFHIGH", - "CF_TICK", - "CF_CLOSE", - "TR.TSVWAP", - "ISODate", - "Jan", - "Feb", - "Mar" -]; -var dataRows = generator.generateRecords(dataTypeFields, { seed: 0, numRows: 100 }); - -var allAvailableColumns = [ - { - checkboxColumn: true, - leftPinned: true - }, - { - field: "userList", - name: "Name", - id: "userList", - filterInput: { - type: "multiselect", - entries: userListEntries - }, - minWidth: 150, - width: 165, - editableContent: true - }, - { - field: "TR.Volume", - name: "Bank Balance", - id: "TR.Volume", - width: 90, - noFitting: true, - textAlign: "right", - heatMap: { - midPoint: 40 - }, - inCellEditing: { - type: "number" - }, - filterInput: { - type: "number" - }, - editableContent: true, - formatType: { - type: "number", - separator: true, - decimalPlaces: 0 - } - }, - { - field: "CF_CLOSE", - id: "CF_CLOSE", - sortable: false, - name: "Price Graph", - filterInput: false, - minWidth: 120, - rangeBar: { - low: "CFLOW", - high: "CFHIGH", - last: "CF_LAST", - close: "CF_CLOSE", - vwap: "TR.TSVWAP", - tick: "CF_TICK", - }, - }, - { - field: "CF_LAST", - id: "CF_LAST", - sortable: false, - name: "Year High Low Range", - minWidth: 150, - filterInput: false, - rangeBar: { - low: "CFLOW", - high: "CFHIGH", - last: "CF_LAST" - } - }, - { - field: "changed", - id: "changed", - name: "Pct. Chng", - dataType: "number", - filterInput: false, - percentBar: { - alignment: "c" - }, - editableContent: true, - noFitting: true, - minWidth: 150 - }, - { - field: "id", - name: "Order", - noFitting: true, - id: "id", - filterInput: { - type: "number" - }, - width: 40, - filterInput: false, - }, - { - field: "CF_TICK", - name: "Tick", - id: "CF_TICK", - noFitting: true, - width: 40, - filterInput: false, - binding: onTickBinding - }, - { - field: "boolean", - name: "Bought", - id: "boolean", - filterInput: false, - noFitting: true, - width: 40, - textAlign: "center", - binding: EFIconFormatter.create({ - icon: { - true: "tick", - false: "cross" - } - }), - inCellEditing: { - type: "checkbox" - }, - editableContent: true - }, - { - field: "ISODate", - id: "ISODate", - name: "Date", - dataType: "datetime", - filterInput: { - type: "date" - }, - noFitting: true, - binding: dateTimePicker.create({ - styles: { - width: 180 - } - }), - width: 180, - alignment: "c" - }, - { - field: "languageList", - id: "languageList", - name: "Language", - editableContent: true, - inCellEditing: { - type: "select", - entries: languageEntries - }, - filterInput: { - type: "select", - entries: languageEntries - }, - minWidth: 120 - }, - { - field: "countryList", - id: "countryList", - name: "Country", - filterInput: false, - textAlign: "c", - binding: EFButtonFormatter.create({ - events: { - click: function (event, context) { - var value = context.getData(context.field); - alert(codeList[value]); - } - } - }), - minWidth: 80 - }, - { - field: "Jan", - id: "Jan", - name: "Jan", - filterInput: { - type: "number" - }, - conditions: dateConditions, - alignment: "c", - formatType: "percent", - minWidth: 80, // Equal to fit content - stackId: "stack1" - }, - { - field: "Feb", - name: "Feb", - id: "Feb", - filterInput: { - type: "number" - }, - conditions: dateConditions, - alignment: "c", - formatType: "percent", - minWidth: 80, - stackId: "stack1" - }, { - field: "Mar", - name: "Mar", - id: "Mar", - filterInput: { - type: "number" - }, - conditions: dateConditions, - alignment: "c", - formatType: "percent", - minWidth: 80, - stackId: "stack1" - } - -]; - -function onTickBinding(e) { - var cell = e.cell; - var data = e.data; - var content = cell.getContent(); - if (!content) { - content = document.createElement("ef-icon"); - } - content.icon = data === 1 ? "arrow-down-fill" : "arrow-up-fill"; - content.style.color = data === 1 ? "rgb(245, 71, 91)" : "rgb(57, 196, 110)"; - cell.setContent(content); -}; - -// generate dynamic data and assign to "efx-grid" -dataSizeSelect.addEventListener("value-changed", function (e) { - var dataRows = generator.generateRecords(dataTypeFields, { seed: 0, numRows: e.detail.value }); - grid.data = dataRows; +remove_btn.addEventListener("click", function(e) { + grid.api.removeRows([0, 1, 2, 3, 4]); }); -// set up row Filter Extension -search_input.addEventListener("keyup", function (e) { - const input = e.currentTarget; - - if (input._prevValue !== input.value) { - input._prevValue = input.value; - filterExt.refresh(); // Force filter triggering - } -}); - -var filterFunc = function (rowData, rowId, context) { - var str = ""; - var val = context.input.value.toLowerCase(); - for (var key in rowData) { - str += rowData[key] + " "; - } - return str.toLowerCase().indexOf(val) > -1; -}; - -var context = { - input: search_input -}; - -filterExt.addGridFilter(filterFunc, context); - -// Prepare model for context-menu -const contextMenuModel = { - items: { - FILTER: { - text: "Filter", - callback: function (e) { - filterExt.openDialog(e.colIndex, { - sortUI: true, // Show Sort area - filterUI: true, // Show Filter area - sortState: "d", // "a" for ascending or "d" for descending - filterChanged: function (e) { // Filter changed handler - console.log(e.detail); - }, - sortChanged: function (e) { // Sort changed handler - console.log(e.detail); - } - }); - } - }, - ROW_COLORING: { - text: "Set Row Color", - items: [ - { text: "Red", value: "#FF0000" }, - { text: "Green", value: "#00FF00" }, - { text: "Blue", value: "#0000FF" }, - { type: "separator" }, - { text: "Default", value: "" } - ], - callback: function (e) { - const { rowIndex, item: { value } } = e; - rowColoring.setRowColor(rowIndex, value); - } - } - }, - onMenu: function (e) { - var context = e.context; - var menu = e.menu; - if (context === "header") { - menu.addItems("FILTER"); - } else if (context === "content") { - menu.addItems(["ROW_COLORING", "FILTER"]); - } - } -}; - -contextMenuExt.listen("contextmenu", function (e) { - // contextmenu event argument provides info about the right click position within the core grid - console.log(e); -}); - -// set up "column-selection-dialog" -var dialog = null; -var selectionDialogConfirmed = function (e) { - var columnCommited = e.detail.data; - columnCommited = columnCommited.map(function (column) { - return { - ...column, // Clone object to retain format - field: nameToField[column.name] - } - }) - grid.api.restoreColumns(columnCommited); -}; - -var nameToField = { - "Name": "userList", - "Order": "id", - "Bought": "boolean", - "Tick": "CF_TICK", - "Bank Balance": "TR.Volume", - "Price Graph": "CF_CLOSE", - "Year High Low Range": "CF_LAST", - "Pct. Chng": "changed", - "Date": "ISODate", - "Country": "countryList", - "Language": "languageList", - "Jan": "Jan", - "Feb": "Feb", - "Mar": "Mar" +var fields = ["id", "companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 22 }); +var configObj = { + columns: [ + { name: "Id", field: fields[0], width: 40, alignment: "center" }, + { name: "Company", field: fields[1] }, + { name: "Market", field: fields[2], width: 120 }, + { name: "Last", field: fields[3], width: 100 }, + { name: "Net. Chng", field: fields[4], width: 100 }, + { name: "Industry", field: fields[5] } + ], + staticDataRows: records }; -selectColumnBtn.addEventListener("click", function () { - if (!dialog) { - dialog = document.createElement("column-selection-dialog"); - dialog.addEventListener("confirm", selectionDialogConfirmed); - } - - var columns = grid.api.getConfigObject().columns; - var visibleColumns = columns.filter(function (column) { - return column.checkboxColumn !== true; - }); - - var allColumns = allAvailableColumns.filter(function (column) { - return column.checkboxColumn !== true; - }); - - var columnObj = allColumns.map(function (column) { - return { - ...column, // Clone object to retain format - field: column.name, - id: nameToField[column.name] - } - }); - visibleColumns = visibleColumns.map(function (column) { - return { - ...column, // Clone object to retain format - field: column.name, - id: column.id - } - }); - dialog.init({ - data: columnObj.slice(), - visibleItems: visibleColumns.slice() - }); - dialog.show(); -}); +var grid = document.getElementById("grid"); +grid.config = configObj; +
+

Non-overlap vertical scrollbar example

+

The Grid vertical scrollbar, by default, is shown on top of the grid. This is to avoid jittering the content when the layout is changed. However, in some cases, the vertical scrollbar may hinder or prevent interaction with the content, especially for the rightmost column. Use the contentRightPadding flag to reserve some space on the right to prevent this from happening.

+

autoHideScrollbar could also be used to stop automatic scrollbar hiding.

+
efx-grid {
+    height: 200px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
 
-var blotterConfig = {
-    scrollbar: true,
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { numRows: 15 });
+var configObj = {
     autoHideScrollbar: false,
-    linearWheelScrolling: true,
-    stepScroll: true,
-    columnGrouping: [
-    {
-        id: "g1",
-        name: "Account Profile",
-        alignment: "center",
-        children: ["userList", "TR.Volume"]
-    },    
-    {
-        id: "g2",
-        name: "Transaction Details",
-        alignment: "center",
-        children: ["id", "CF_TICK", "boolean"]
-    },
-    {
-        id: "g3",
-        name: "Financial Overview",
-        alignment: "center",
-        children: ["CF_CLOSE", "CF_LAST", "changed"]
-    },
-    {
-        id: "g4",
-        name: "Localization Information",
-        children: ["ISODate", "languageList", "countryList"]
-    }],
-    extensions: [
-        columnGroupingExt,
-        checkboxExt,
-        rowGroupingExt,
-        conditionalColoringExt,
-        cellSelectionExt,
-        filterInputExt,
-        columnResizingExt,
-        textFormattingExt,
-        heatMapExt,
-        inCellEditingExt,
-        percentBarExt,
-        filterExt,
-        contextMenuExt,
-        rowColoring,
-        columnFitterExt,
-        columnStackExt,
-        rangeBarExt,
+    contentRightPadding: 14,
+    columns: [
+        {name: "Company", field: fields[0]},
+        {name: "Market", field: fields[1], width: 100},
+        {name: "Last", field: fields[2], width: 80},
+        {name: "Net. Chng", field: fields[3], width: 80},
+        {name: "Industry", field: fields[4]}
     ],
-    inCellEditing: {
-        type: "input",
-        contentSource: "field",
-        autoCommitText: true,
-        beforeCommit: function (e) {
-            // console.log("beforeCommit", e)
-        }
-    },
-    contextMenu: contextMenuModel,
-    columnStack: {
-        menuElement: document.getElementById("popup_menu")
-    },
-    columnFitting: {
-        title: false,
-        autoAdjust: true,
-        paddingSize: 20
-    }
+    staticDataRows: records
 };
 
-grid.columns = allAvailableColumns;
-grid.config = blotterConfig;
-grid.data = dataRows;
-
-column_grouping_selector.addEventListener("opened-changed", function (e) {
-    if (!this.opened) {
-        var columns = [{
-            field: "userList",
-            name: "Name"
-        }, {
-            field: "languageList",
-            name: "Language",
-        }, {
-            field: "countryList",
-            name: "Country",
-        }];
-        var filtered = columns.filter(function (column) {
-            return column.checkboxColumn !== true;
-        });
-        var data = filtered.map(function (column) {
-            return {
-                label: column.name,
-                value: column.field
-            }
-        });
-        var criteria = rowGroupingExt.getGroupingCriteria();
-        var selectorData = data.filter(function (item) {
-            return criteria.indexOf(item.value) < 0;
-        });
-
-        column_grouping_selector.data = selectorData;
-    }
-});
-
-function onPillRemove(e) {
-    // Remove Pill
-    var pill = e.target;
-    pill.parentElement.removeChild(pill._arrow);
-    pill.parentElement.removeChild(pill);
-    var field = pill.value;
-
-    // Update grouping criteria
-    var criteria = rowGroupingExt.getGroupingCriteria().slice(0);
-    criteria.splice(criteria.indexOf(field), 1);
-    rowGroupingExt.setGroupingCriteria(criteria);
-}
-
-column_grouping_selector.addEventListener("value-changed", function (e) {
-    var value = e.detail.value;
-    var label = this.label;
-
-    // Insert Pill
-    var pill = document.createElement("ef-pill");
-
-    var arrow = document.createElement("ef-icon");
-    arrow.className = "arrow";
-    arrow.setAttribute('icon', 'right');
-
-    pill._arrow = arrow;
-    pill.setAttribute("clears", "");
-    pill.innerText = label;
-    pill.value = value;
-    pill.addEventListener("clear", onPillRemove);
-
-    var container = document.getElementById("grouping");
-    container.appendChild(pill);
-    container.appendChild(arrow);
-
-    this.value = "";
-
-    // Update grouping criteria
-    var criteria = rowGroupingExt.getGroupingCriteria();
-    var criteria = criteria.concat([value]);
-    rowGroupingExt.setGroupingCriteria(criteria);
-});
+var grid = document.getElementById("grid");
+grid.config = configObj;
 
-

As seen above, the showcase includes a combination of features and extensions which allow Grid to support any data types as well as data visualization.

-

The most commonly used features have been included in this showcase, such as sorting, filtering, and column moving.

-

The extensions show how they can leverage Grid so it can support many use cases. The following offers a brief explanation about some of their usage:

-
    -
  1. In-cell Editing Extension allows the data manipulation to be made, under the 'Name' and 'Bought' columns, any row-data in any type can be changed.
  2. -
  3. By clicking on the button under the 'Country' column, will a dialog box pops up, showing the full country name using the Formatter.
  4. -
  5. Heat Map Extension uses in the 'Bank Balance' column to provide the coloring for the columns field to present the balance health.
  6. -
  7. Percent Bar Extension uses in the 'Rating' column allow the showcase to render the data in the bar.
  8. -
  9. By scrolling to the right panel of the Grid, Conditional Coloring Extension applies to differentiate the percentage values making it easy to analyze the data.
  10. -
  11. The 'Group By' dropdown option utilizes an additional UI customization with the Grid's API extension in this showcase resulting an useful UI feature as a ef-pill.
  12. -
  13. The total data size option for the data rendering can also be adjusted to see the performance of the row virtualization feature.
  14. -
-

The showcase includes all the following Grid features and extensions:

-
    -
  • Conditional Coloring Extension,
  • -
  • Column Grouping Extension,
  • -
  • Checkbox Extension,
  • -
  • Cell Selection Extension,
  • -
  • Filter Input Extension,
  • -
  • Column Resizing Extension,
  • -
  • Text Formatting Extension,
  • -
  • Heat Map Extension,
  • -
  • In Cell Editing Extension,
  • -
  • Percent Bar Extension,
  • -
  • Row Filtering Extension,
  • -
  • Context Menu Extension,
  • -
  • Row Coloring Extension,
  • -
  • Column Fitter Extension,
  • -
  • Column Stack Extension,
  • -
  • Range Bar Extension,
  • -
  • Coral Button Formatter,
  • -
  • Coral Icon Formatter,
  • -
  • Custom Formatter,
  • -
  • Date Time Formatter
  • -
  • column-selection-dialog,
  • -
  • filter-dialog
  • -
+
+
+
\ No newline at end of file diff --git a/template-137.html b/template-137.html index 75a72713..1096ff56 100644 --- a/template-137.html +++ b/template-137.html @@ -1,131 +1,61 @@ -

Grid Builder / Loader

-

Grid Builder

-

The grid configuration builder provide a quick start way of using grid in your application. This will help new users to getting started with grid easier. You can try with different grid customization and grid extensions with a realtime result, then this configuration can be copy and paste into any application to get the same result as seen from this section.

-
<style>
-    .main-layout {
-        height: 800px;
-        display: flex;
-    }
-    .content-title {
-        padding-top: 5px;
-        padding-bottom: 5px;
-        font-size: 14px;
-    }
-    .main-content {
-        flex: 1;
-        display: flex;
-        flex-direction: column;
-    }
-    #grid {
-        height: 350px;
-    }
-    div {
-        min-height: 24px;
-    }
-    hr  {
-        margin-top: 15px;
-        margin-bottom: 15px;
-        width: 100%;
-    }
-    label {
-        padding-right: 10px;
-    }
-    #configArea {
-        flex: 1;
-        width: 100%;
-        margin-top: 10px;
-        font-family: monospace;
-    }
-    #section-detail{
-        height: 160px;
-        overflow-y: scroll;
-        padding-bottom: 10px;
-        border: grey solid 1px;
-    }
-    .two-columns {
-        display: grid;
-        grid-template-columns: 1fr 1fr;
-    }
-    .two-columns > *:not(hr) {
-        padding:2px;
-        display: flex;
-        align-items: center;
-    }
-</style>
-
-<ef-sidebar-layout sidebar-width="0px" class="main-layout">
-    <ef-panel slot="main-content" class="main-content" spacing>
-        <ef-tab-bar id="tabs"></ef-tab-bar>
-        <ef-panel spacing>
-            <div id="section-detail"></div>
-        </ef-panel>
-        <efx-grid id="grid"></efx-grid>
-        <ef-overlay-menu id="menu"></ef-overlay-menu>
-        <textarea id="configArea"></textarea>
-    </ef-panel>
-</ef-sidebar-layout>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-import './resources/grid-builder-app.min.js'
-
-

Grid Loader

-

In this section, you can try to paste your configuration object here to see an live result. This allow user to make advance customization to grid configuration object before using with their real application.

-
.main-layout {
-    height: 800px;
-    display: flex;
-    flex-direction: column;
+

Showcase

+
body {
+    padding: 24px;
 }
-.content-title {
-    padding-top: 5px;
-    padding-bottom: 5px;
-    font-size: 14px;
-}
-.main-content {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
+
+efx-grid {
+    height: 600px;
 }
-#container {
-    height: 400px;
+
+#grouping .arrow {
+    color: red;
+    margin: 0 5px;
+    vertical-align: middle;
 }
-#grid{
-    height: 100%;
+
+#grouping .arrow:last-child {
+    display: none;
 }
-div {
-    min-height: 24px;
+
+ef-pill {
+    margin: auto;
 }
-hr  {
-    margin-top: 15px;
-    margin-bottom: 15px;
+
+#column_grouping_selector {
+    margin-right: 5px;
 }
-#configArea {
-    width: 100%;
-    padding-top: 15px;
-    height: 300px;
-    margin-bottom: 8px;
-    font-family: monospace;
+
+hr {
+    margin: 8px;
 }
 
-
<ef-sidebar-layout sidebar-width="0px" class="main-layout">
-    <ef-header slot="main-header" level="1">
-        <ef-button id="run" icon="play">RUN</ef-icon></ef-button>
-    </ef-header>
-    <ef-panel slot="main-content" class="main-content" spacing>
-        <textarea id="configArea"></textarea>
-        <div id="container">
-            <efx-grid id="grid"></efx-grid>
-        </div>
-        <ef-overlay-menu id="menu"></ef-overlay-menu>
-    </ef-panel>
-</ef-sidebar-layout>
+
<fieldset>
+    <legend>Operation</legend>
+    <span>
+        <ef-button id="select_column_btn">Select Columns</ef-button>
+        Data Size:
+        <ef-select id="dataSize">
+            <ef-item value="10">10 Rows</ef-item>
+            <ef-item value="100" selected>100 Rows</ef-item>
+            <ef-item value="1000">1,000 Rows</ef-item>
+            <ef-item value="10000">10,000 Rows</ef-item>
+            <ef-item value="100000">100,000 Rows</ef-item>
+        </ef-select>
+    </span>
+    <hr>
+    <span>
+        <label for="search_input">Filter: </label>
+        <input id="search_input" type="search" placeholder="Filter any column">
+    </span>
+    <hr>
+    <div id="grouping">
+        <ef-select id="column_grouping_selector" placeholder="Group By"></ef-select>
+    </div>
+</fieldset>
+<hr>
+
+<efx-grid id="preview"></efx-grid>
+<ef-overlay-menu id="popup_menu"></ef-overlay-menu>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -136,6 +66,713 @@ 

Grid Builder

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -import './resources/grid-loader-app.min.js' +var checkboxExt = new Checkbox(); +var rowGroupingExt = new RowGrouping(); +var conditionalColoringExt = new ConditionalColoring(); +var columnGroupingExt = new ColumnGrouping(); +var cellSelectionExt = new CellSelection(); +var filterInputExt = new FilterInput(); +var columnResizingExt = new ColumnResizing(); +var textFormattingExt = new TextFormatting(); +var heatMapExt = new HeatMap(); +var inCellEditingExt = new InCellEditing(); +var percentBarExt = new PercentBar(); +var filterExt = new RowFiltering(); +var rowColoring = new RowColoring(); +var contextMenuExt = new ContextMenu(); +var columnFitterExt = new ColumnFitter(); +var columnStackExt = new ColumnStack(); +var rangeBarExt = new RangeBar(); +var generator = DataGenerator; +var dateTimePicker = tr.EmeraldDateTimePickerFormatter ? tr.EmeraldDateTimePickerFormatter : EFDateTimePickerFormatter; // WORKAROUND: for datetime picker in v6 + +var grid = window.grid = document.getElementsByTagName("efx-grid")[0]; +var dataSizeSelect = document.getElementById("dataSize"); +var selectColumnBtn = document.getElementById("select_column_btn"); + +var userList = [ + "Amanda Herrera", + "Josh Robertson", + "Abbie Parker", + "Christopher Washington", + "Casey Alvarez", + "Joshua Castillo", + "Skye Wilson", + "Tommy Medina", + "Vincent Smith", + "Jackson Garcia", + "Lisa Alexander", + "Holly Brooks", + "Zara Marshall", + "Kiera Shaw" +]; +const userListEntries = userList.map(function (item) { + return { + label: item, + value: item + }; +}); + +var codeList = { + "FRA": "France", + "GBR": "United Kingdom", + "ISL": "Iceland", + "ITA": "Italy", + "PRT": "Protugal", + "SWE": "Sweden", + "GRC": "Greece", + "DEU": "Germany", + "NOR": "Norway", + "IND": "India", + "CHN": "China" +}; + +var languageList = ["French", "English", "German", "Italian", "Portuguese", "Chinese"]; + +const languageEntries = languageList.map(function (item) { + return { + label: item, + value: item + }; +}); + +generator.addFieldInfo("userList", { + type: "set", + members: userList +}) + +generator.addFieldInfo("languageList", { + type: "set", + members: languageList +}); + +generator.addFieldInfo("countryList", { + type: "set", + members: ["FRA", "GBR", "ISL", "ITA", "PRT", "SWE", "GRC", "DEU", "NOR", "GBR", "IND", "FRA", "DEU", "CHN" + ] +}) + + +generator.addFieldInfo("CF_CLOSE", { + type: "number", + min: 0, + max: 1000, + prec: 2 +}); + +generator.addFieldInfo("TR.TSVWAP", { + type: "number", + min: 0, + max: 1000, + prec: 2 +}); + +generator.addFieldInfo("Jan", { + type: "number", + min: -100, + max: 100, + prec: 2 +}); + +generator.addFieldInfo("Feb", { + type: "number", + min: -100, + max: 100, + prec: 2 +}); + +generator.addFieldInfo("Mar", { + type: "number", + min: -100, + max: 100, + prec: 2 +}); + +generator.addFieldInfo("changed", { + type: "number", + min: -100, + max: 100, + prec: 2 +}); + +var dateConditions = [ + { + expression: ["GT", 60], + backgroundColor: "#b9f6ca66" + }, + { + expression: ["LT", 20], + backgroundColor: "#ff80ab66" + }, +]; + +var dataTypeFields = [ + "id", + "userList", + "languageList", + "countryList", + "boolean", // Bought + "TR.Volume", // Bank Balance + "changed", // Rating + "CFLOW", + "CF_LAST", + "CFHIGH", + "CF_TICK", + "CF_CLOSE", + "TR.TSVWAP", + "ISODate", + "Jan", + "Feb", + "Mar" +]; +var dataRows = generator.generateRecords(dataTypeFields, { seed: 0, numRows: 100 }); + +var allAvailableColumns = [ + { + checkboxColumn: true, + leftPinned: true + }, + { + field: "userList", + name: "Name", + id: "userList", + filterInput: { + type: "multiselect", + entries: userListEntries + }, + minWidth: 150, + width: 165, + editableContent: true + }, + { + field: "TR.Volume", + name: "Bank Balance", + id: "TR.Volume", + width: 90, + noFitting: true, + textAlign: "right", + heatMap: { + midPoint: 40 + }, + inCellEditing: { + type: "number" + }, + filterInput: { + type: "number" + }, + editableContent: true, + formatType: { + type: "number", + separator: true, + decimalPlaces: 0 + } + }, + { + field: "CF_CLOSE", + id: "CF_CLOSE", + sortable: false, + name: "Price Graph", + filterInput: false, + minWidth: 120, + rangeBar: { + low: "CFLOW", + high: "CFHIGH", + last: "CF_LAST", + close: "CF_CLOSE", + vwap: "TR.TSVWAP", + tick: "CF_TICK", + }, + }, + { + field: "CF_LAST", + id: "CF_LAST", + sortable: false, + name: "Year High Low Range", + minWidth: 150, + filterInput: false, + rangeBar: { + low: "CFLOW", + high: "CFHIGH", + last: "CF_LAST" + } + }, + { + field: "changed", + id: "changed", + name: "Pct. Chng", + dataType: "number", + filterInput: false, + percentBar: { + alignment: "c" + }, + editableContent: true, + noFitting: true, + minWidth: 150 + }, + { + field: "id", + name: "Order", + noFitting: true, + id: "id", + filterInput: { + type: "number" + }, + width: 40, + filterInput: false, + }, + { + field: "CF_TICK", + name: "Tick", + id: "CF_TICK", + noFitting: true, + width: 40, + filterInput: false, + binding: onTickBinding + }, + { + field: "boolean", + name: "Bought", + id: "boolean", + filterInput: false, + noFitting: true, + width: 40, + textAlign: "center", + binding: EFIconFormatter.create({ + icon: { + true: "tick", + false: "cross" + } + }), + inCellEditing: { + type: "checkbox" + }, + editableContent: true + }, + { + field: "ISODate", + id: "ISODate", + name: "Date", + dataType: "datetime", + filterInput: { + type: "date" + }, + noFitting: true, + binding: dateTimePicker.create({ + styles: { + width: 180 + } + }), + width: 180, + alignment: "c" + }, + { + field: "languageList", + id: "languageList", + name: "Language", + editableContent: true, + inCellEditing: { + type: "select", + entries: languageEntries + }, + filterInput: { + type: "select", + entries: languageEntries + }, + minWidth: 120 + }, + { + field: "countryList", + id: "countryList", + name: "Country", + filterInput: false, + textAlign: "c", + binding: EFButtonFormatter.create({ + events: { + click: function (event, context) { + var value = context.getData(context.field); + alert(codeList[value]); + } + } + }), + minWidth: 80 + }, + { + field: "Jan", + id: "Jan", + name: "Jan", + filterInput: { + type: "number" + }, + conditions: dateConditions, + alignment: "c", + formatType: "percent", + minWidth: 80, // Equal to fit content + stackId: "stack1" + }, + { + field: "Feb", + name: "Feb", + id: "Feb", + filterInput: { + type: "number" + }, + conditions: dateConditions, + alignment: "c", + formatType: "percent", + minWidth: 80, + stackId: "stack1" + }, { + field: "Mar", + name: "Mar", + id: "Mar", + filterInput: { + type: "number" + }, + conditions: dateConditions, + alignment: "c", + formatType: "percent", + minWidth: 80, + stackId: "stack1" + } + +]; + +function onTickBinding(e) { + var cell = e.cell; + var data = e.data; + var content = cell.getContent(); + if (!content) { + content = document.createElement("ef-icon"); + } + content.icon = data === 1 ? "arrow-down-fill" : "arrow-up-fill"; + content.style.color = data === 1 ? "rgb(245, 71, 91)" : "rgb(57, 196, 110)"; + cell.setContent(content); +}; + +// generate dynamic data and assign to "efx-grid" +dataSizeSelect.addEventListener("value-changed", function (e) { + var dataRows = generator.generateRecords(dataTypeFields, { seed: 0, numRows: e.detail.value }); + grid.data = dataRows; +}); + +// set up row Filter Extension +search_input.addEventListener("keyup", function (e) { + const input = e.currentTarget; + + if (input._prevValue !== input.value) { + input._prevValue = input.value; + filterExt.refresh(); // Force filter triggering + } +}); + +var filterFunc = function (rowData, rowId, context) { + var str = ""; + var val = context.input.value.toLowerCase(); + for (var key in rowData) { + str += rowData[key] + " "; + } + return str.toLowerCase().indexOf(val) > -1; +}; + +var context = { + input: search_input +}; + +filterExt.addGridFilter(filterFunc, context); + +// Prepare model for context-menu +const contextMenuModel = { + items: { + FILTER: { + text: "Filter", + callback: function (e) { + filterExt.openDialog(e.colIndex, { + sortUI: true, // Show Sort area + filterUI: true, // Show Filter area + sortState: "d", // "a" for ascending or "d" for descending + filterChanged: function (e) { // Filter changed handler + console.log(e.detail); + }, + sortChanged: function (e) { // Sort changed handler + console.log(e.detail); + } + }); + } + }, + ROW_COLORING: { + text: "Set Row Color", + items: [ + { text: "Red", value: "#FF0000" }, + { text: "Green", value: "#00FF00" }, + { text: "Blue", value: "#0000FF" }, + { type: "separator" }, + { text: "Default", value: "" } + ], + callback: function (e) { + const { rowIndex, item: { value } } = e; + rowColoring.setRowColor(rowIndex, value); + } + } + }, + onMenu: function (e) { + var context = e.context; + var menu = e.menu; + if (context === "header") { + menu.addItems("FILTER"); + } else if (context === "content") { + menu.addItems(["ROW_COLORING", "FILTER"]); + } + } +}; + +contextMenuExt.listen("contextmenu", function (e) { + // contextmenu event argument provides info about the right click position within the core grid + console.log(e); +}); + +// set up "column-selection-dialog" +var dialog = null; +var selectionDialogConfirmed = function (e) { + var columnCommited = e.detail.data; + columnCommited = columnCommited.map(function (column) { + return { + ...column, // Clone object to retain format + field: nameToField[column.name] + } + }) + grid.api.restoreColumns(columnCommited); +}; + +var nameToField = { + "Name": "userList", + "Order": "id", + "Bought": "boolean", + "Tick": "CF_TICK", + "Bank Balance": "TR.Volume", + "Price Graph": "CF_CLOSE", + "Year High Low Range": "CF_LAST", + "Pct. Chng": "changed", + "Date": "ISODate", + "Country": "countryList", + "Language": "languageList", + "Jan": "Jan", + "Feb": "Feb", + "Mar": "Mar" +}; + +selectColumnBtn.addEventListener("click", function () { + if (!dialog) { + dialog = document.createElement("column-selection-dialog"); + dialog.addEventListener("confirm", selectionDialogConfirmed); + } + + var columns = grid.api.getConfigObject().columns; + var visibleColumns = columns.filter(function (column) { + return column.checkboxColumn !== true; + }); + + var allColumns = allAvailableColumns.filter(function (column) { + return column.checkboxColumn !== true; + }); + + var columnObj = allColumns.map(function (column) { + return { + ...column, // Clone object to retain format + field: column.name, + id: nameToField[column.name] + } + }); + visibleColumns = visibleColumns.map(function (column) { + return { + ...column, // Clone object to retain format + field: column.name, + id: column.id + } + }); + dialog.init({ + data: columnObj.slice(), + visibleItems: visibleColumns.slice() + }); + dialog.show(); +}); + +var blotterConfig = { + scrollbar: true, + autoHideScrollbar: false, + linearWheelScrolling: true, + stepScroll: true, + columnGrouping: [ + { + id: "g1", + name: "Account Profile", + alignment: "center", + children: ["userList", "TR.Volume"] + }, + { + id: "g2", + name: "Transaction Details", + alignment: "center", + children: ["id", "CF_TICK", "boolean"] + }, + { + id: "g3", + name: "Financial Overview", + alignment: "center", + children: ["CF_CLOSE", "CF_LAST", "changed"] + }, + { + id: "g4", + name: "Localization Information", + children: ["ISODate", "languageList", "countryList"] + }], + extensions: [ + columnGroupingExt, + checkboxExt, + rowGroupingExt, + conditionalColoringExt, + cellSelectionExt, + filterInputExt, + columnResizingExt, + textFormattingExt, + heatMapExt, + inCellEditingExt, + percentBarExt, + filterExt, + contextMenuExt, + rowColoring, + columnFitterExt, + columnStackExt, + rangeBarExt, + ], + inCellEditing: { + type: "input", + contentSource: "field", + autoCommitText: true, + beforeCommit: function (e) { + // console.log("beforeCommit", e) + } + }, + contextMenu: contextMenuModel, + columnStack: { + menuElement: document.getElementById("popup_menu") + }, + columnFitting: { + title: false, + autoAdjust: true, + paddingSize: 20 + } +}; + +grid.columns = allAvailableColumns; +grid.config = blotterConfig; +grid.data = dataRows; + +column_grouping_selector.addEventListener("opened-changed", function (e) { + if (!this.opened) { + var columns = [{ + field: "userList", + name: "Name" + }, { + field: "languageList", + name: "Language", + }, { + field: "countryList", + name: "Country", + }]; + var filtered = columns.filter(function (column) { + return column.checkboxColumn !== true; + }); + var data = filtered.map(function (column) { + return { + label: column.name, + value: column.field + } + }); + var criteria = rowGroupingExt.getGroupingCriteria(); + var selectorData = data.filter(function (item) { + return criteria.indexOf(item.value) < 0; + }); + + column_grouping_selector.data = selectorData; + } +}); + +function onPillRemove(e) { + // Remove Pill + var pill = e.target; + pill.parentElement.removeChild(pill._arrow); + pill.parentElement.removeChild(pill); + var field = pill.value; + + // Update grouping criteria + var criteria = rowGroupingExt.getGroupingCriteria().slice(0); + criteria.splice(criteria.indexOf(field), 1); + rowGroupingExt.setGroupingCriteria(criteria); +} + +column_grouping_selector.addEventListener("value-changed", function (e) { + var value = e.detail.value; + var label = this.label; + + // Insert Pill + var pill = document.createElement("ef-pill"); + + var arrow = document.createElement("ef-icon"); + arrow.className = "arrow"; + arrow.setAttribute('icon', 'right'); + + pill._arrow = arrow; + pill.setAttribute("clears", ""); + pill.innerText = label; + pill.value = value; + pill.addEventListener("clear", onPillRemove); + + var container = document.getElementById("grouping"); + container.appendChild(pill); + container.appendChild(arrow); + + this.value = ""; + + // Update grouping criteria + var criteria = rowGroupingExt.getGroupingCriteria(); + var criteria = criteria.concat([value]); + rowGroupingExt.setGroupingCriteria(criteria); +});
- \ No newline at end of file +

As seen above, the showcase includes a combination of features and extensions which allow Grid to support any data types as well as data visualization.

+

The most commonly used features have been included in this showcase, such as sorting, filtering, and column moving.

+

The extensions show how they can leverage Grid so it can support many use cases. The following offers a brief explanation about some of their usage:

+
    +
  1. In-cell Editing Extension allows the data manipulation to be made, under the 'Name' and 'Bought' columns, any row-data in any type can be changed.
  2. +
  3. By clicking on the button under the 'Country' column, will a dialog box pops up, showing the full country name using the Formatter.
  4. +
  5. Heat Map Extension uses in the 'Bank Balance' column to provide the coloring for the columns field to present the balance health.
  6. +
  7. Percent Bar Extension uses in the 'Rating' column allow the showcase to render the data in the bar.
  8. +
  9. By scrolling to the right panel of the Grid, Conditional Coloring Extension applies to differentiate the percentage values making it easy to analyze the data.
  10. +
  11. The 'Group By' dropdown option utilizes an additional UI customization with the Grid's API extension in this showcase resulting an useful UI feature as a ef-pill.
  12. +
  13. The total data size option for the data rendering can also be adjusted to see the performance of the row virtualization feature.
  14. +
+

The showcase includes all the following Grid features and extensions:

+
    +
  • Conditional Coloring Extension,
  • +
  • Column Grouping Extension,
  • +
  • Checkbox Extension,
  • +
  • Cell Selection Extension,
  • +
  • Filter Input Extension,
  • +
  • Column Resizing Extension,
  • +
  • Text Formatting Extension,
  • +
  • Heat Map Extension,
  • +
  • In Cell Editing Extension,
  • +
  • Percent Bar Extension,
  • +
  • Row Filtering Extension,
  • +
  • Context Menu Extension,
  • +
  • Row Coloring Extension,
  • +
  • Column Fitter Extension,
  • +
  • Column Stack Extension,
  • +
  • Range Bar Extension,
  • +
  • Coral Button Formatter,
  • +
  • Coral Icon Formatter,
  • +
  • Custom Formatter,
  • +
  • Date Time Formatter
  • +
  • column-selection-dialog,
  • +
  • filter-dialog
  • +
diff --git a/template-138.html b/template-138.html index 90d13f8d..75a72713 100644 --- a/template-138.html +++ b/template-138.html @@ -1,22 +1,69 @@ -

Job Manager

-
body {
-    padding: 24px;
-}
-
-efx-grid {
-    height: 300px;
-}
+

Grid Builder / Loader

+

Grid Builder

+

The grid configuration builder provide a quick start way of using grid in your application. This will help new users to getting started with grid easier. You can try with different grid customization and grid extensions with a realtime result, then this configuration can be copy and paste into any application to get the same result as seen from this section.

+
<style>
+    .main-layout {
+        height: 800px;
+        display: flex;
+    }
+    .content-title {
+        padding-top: 5px;
+        padding-bottom: 5px;
+        font-size: 14px;
+    }
+    .main-content {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+    }
+    #grid {
+        height: 350px;
+    }
+    div {
+        min-height: 24px;
+    }
+    hr  {
+        margin-top: 15px;
+        margin-bottom: 15px;
+        width: 100%;
+    }
+    label {
+        padding-right: 10px;
+    }
+    #configArea {
+        flex: 1;
+        width: 100%;
+        margin-top: 10px;
+        font-family: monospace;
+    }
+    #section-detail{
+        height: 160px;
+        overflow-y: scroll;
+        padding-bottom: 10px;
+        border: grey solid 1px;
+    }
+    .two-columns {
+        display: grid;
+        grid-template-columns: 1fr 1fr;
+    }
+    .two-columns > *:not(hr) {
+        padding:2px;
+        display: flex;
+        align-items: center;
+    }
+</style>
 
-hr {
-    margin: 8px;
-}
-#search_input {
-    width: 100%;
-}
-
-
<input id="search_input" placeholder="Search Anything..." type="search">
-<hr>
-<efx-grid id="grid"></efx-grid>
+<ef-sidebar-layout sidebar-width="0px" class="main-layout">
+    <ef-panel slot="main-content" class="main-content" spacing>
+        <ef-tab-bar id="tabs"></ef-tab-bar>
+        <ef-panel spacing>
+            <div id="section-detail"></div>
+        </ef-panel>
+        <efx-grid id="grid"></efx-grid>
+        <ef-overlay-menu id="menu"></ef-overlay-menu>
+        <textarea id="configArea"></textarea>
+    </ef-panel>
+</ef-sidebar-layout>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -27,145 +74,68 @@ 

Job Manager

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -DataGenerator.addFieldInfo("status", { - type: "set", - members: ["Success", "Fail", "Partial Success"] -}); - -DataGenerator.addFieldInfo("jobName", { - type: "set", - members: [ - "Docs_Conv_021123_2", - "UPLD_Documents_031123_3", - "ConvUpld_Files_041123_1", - "Upload_Batch_051123_4", - "Files_Upld_061123_5", - "Upld_Conversion_071123", - "Documents_Upload_081123_1", - "Conv_Uploads_091123_2", - "Upload_Files_101123_3", - "Upld_Doc_111123_4", - "Conversion_Upload_121123_5", - "Uploads_Docs_131123_1", - "Docs_Conversion_141123_2", - "Upld_Batch_151123_3", - "Conversion_Batch_161123_4", - "Batch_Upload_171123_5", - "Upld_Documents_181123_1", - "Upload_Conv_191123_2", - "Conversion_Docs_201123_3", - "Upld_Files_211123_4" - ] -}); - -var rowSelection = new RowSelection(); -var inCellEditing = new InCellEditing(); -var rowFiltering = new RowFiltering(); -// Extensions -var fields = ["jobName", "status"]; -var records = DataGenerator.generateRecords(fields, { numRows: 50, seed: 0 }); -var config1 = { - columns: [ - { - title: "Job Name", - field: fields[0], - editableContent: true - }, - { - title: "Status", - field: fields[1], - width: 100 - }, - { - name: "Action", field: fields[1], - width: 150, - titleAlignment: "center", - binding: onActionBinding - } - ], - staticDataRows: records, - rowFiltering: { - iconActivation: "onHover" - }, - extensions: [rowSelection, inCellEditing, rowFiltering] -}; - -function onActionBinding(e) { - var data = e.data; - var cell = e.cell; - var content = cell.getContent(); - if (!content) { - content = document.createElement("div"); - - var editIcon = document.createElement("ef-icon"); - editIcon.icon = "edit"; - editIcon.style.cursor = "pointer"; - editIcon.style.verticalAlign = "middle"; - editIcon.addEventListener("click", onEditClicked); - - var deleteIcon = document.createElement("ef-icon"); - deleteIcon.icon = "trash"; - deleteIcon.style.cursor = "pointer"; - deleteIcon.style.verticalAlign = "middle"; - deleteIcon.addEventListener("click", onRemoveClicked); - - var runButton = document.createElement("ef-button"); - runButton.textContent = "Run"; - runButton.style.verticalAlign = "middle"; - runButton.addEventListener("click", onRunClicked); - - content.appendChild(editIcon); - content.appendChild(deleteIcon); - content.appendChild(runButton); - } - cell.setContent(content); +import './resources/grid-builder-app.min.js' +
+

Grid Loader

+

In this section, you can try to paste your configuration object here to see an live result. This allow user to make advance customization to grid configuration object before using with their real application.

+
.main-layout {
+    height: 800px;
+    display: flex;
+    flex-direction: column;
 }
-
-function onRunClicked(e) {
-    var button = e.currentTarget;
-    var pos = grid.api.getRelativePosition(e);
-    var rowIndex = pos.rowIndex;
-    alert("Click :" + rowIndex);
+.content-title {
+    padding-top: 5px;
+    padding-bottom: 5px;
+    font-size: 14px;
 }
-function onRemoveClicked(e) {
-    var button = e.currentTarget;
-    var pos = grid.api.getRelativePosition(e);
-    var rowIndex = pos.rowIndex;
-    grid.api.removeRow(rowIndex);
+.main-content {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
 }
-function onEditClicked(e) {
-    var button = e.currentTarget;
-    var pos = grid.api.getRelativePosition(e);
-    var rowIndex = + pos.rowIndex;
-    inCellEditing.openEditor(0, rowIndex);
+#container {
+    height: 400px;
 }
+#grid{
+    height: 100%;
+}
+div {
+    min-height: 24px;
+}
+hr  {
+    margin-top: 15px;
+    margin-bottom: 15px;
+}
+#configArea {
+    width: 100%;
+    padding-top: 15px;
+    height: 300px;
+    margin-bottom: 8px;
+    font-family: monospace;
+}
+
+
<ef-sidebar-layout sidebar-width="0px" class="main-layout">
+    <ef-header slot="main-header" level="1">
+        <ef-button id="run" icon="play">RUN</ef-icon></ef-button>
+    </ef-header>
+    <ef-panel slot="main-content" class="main-content" spacing>
+        <textarea id="configArea"></textarea>
+        <div id="container">
+            <efx-grid id="grid"></efx-grid>
+        </div>
+        <ef-overlay-menu id="menu"></ef-overlay-menu>
+    </ef-panel>
+</ef-sidebar-layout>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
 
-var grid = window.grid = document.getElementById("grid");
-grid.config = config1;
-
-var searchInput = document.getElementById("search_input");
-searchInput.addEventListener("keyup", function (e) {
-    var input = e.currentTarget;
-    if (input._prevValue !== input.value) {
-        input._prevValue = input.value;
-        rowFiltering.refresh(); // Force filter triggering
-    }
-});
-
-function filterFunc(rowData, rowId, context) {
-    var str = "";
-    var val = context.input.value.toLowerCase();
-    for (var key in rowData) {
-        str += rowData[key] + " ";
-    }
-    return str.toLowerCase().indexOf(val) > -1;
-};
-
-var context = {
-    input: searchInput
-};
-rowFiltering.addGridFilter(filterFunc, context);
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+import './resources/grid-loader-app.min.js'
 
-

In the example above, we show how to create a grid for managing data. This grid lets users filter, add, edit, and remove data in the grid itself. We used three main features: row filtering, in cell editing, and row selection.

-

Row filtering lets users type in a box to search and filter data across all columns in the grid. Row selection allows users to pick one or more rows in the grid.

-

In cell editing is about changing the data in the grid directly. For our example, we changed the "Job Name" using this feature.

+ \ No newline at end of file diff --git a/template-139.html b/template-139.html index 68a2bb7e..90d13f8d 100644 --- a/template-139.html +++ b/template-139.html @@ -1,5 +1,5 @@ -

Realtime Data

-
body {
+

Job Manager

+
body {
     padding: 24px;
 }
 
@@ -10,8 +10,13 @@ 

Realtime Data

hr { margin: 8px; } +#search_input { + width: 100%; +}
-
<efx-grid id="grid"></efx-grid>
+
<input id="search_input" placeholder="Search Anything..." type="search">
+<hr>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -22,570 +27,145 @@ 

Realtime Data

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var heatMapExt = new HeatMap(); - var textFormattingExt = new TextFormatting(); - var contextMenuExt = new ContextMenu(); - var rowColoringExt = new RowColoring(); - var inCellEditingExt = new InCellEditing(); - var rowSelectionExt = new RowSelection(); - - var grid = document.getElementById("grid"); - var Toolkit = tr.MockRTK ? tr.MockRTK : MockRTK; - Toolkit.init({ ID: 'rtk-efx-grid', minInterval: 100, maxInterval: 800 }, ['Quotes', 'Data']).then(onInit); - function onInit(rtk) { - const contextMenuModel = { - items: { - INSERT_ROW: { - text: "Insert Row", - callback: function (e) { - var rowIndex = e.rowIndex; - grid.api.insertRow({}, rowIndex); - inCellEditingExt.openEditor(0, rowIndex); - } - }, - REMOVE_ROW: { - text: "Remove Row", - callback: function (e) { - var selectionRows = rowSelectionExt.getSelectedRows(); - grid.api.removeRows(selectionRows); - } - } - }, - onMenu: function (e) { - var context = e.context; - var menu = e.menu; - var rowIndex = e.rowIndex; - if (context === "content") { - if (grid.api.getRowDefinition(rowIndex).getType() !== "CONSTITUENT") { - menu.addItems(["INSERT_ROW", "REMOVE_ROW"]); - } else { - menu.addItems(["INSERT_ROW"]); - } - } - } - }; +DataGenerator.addFieldInfo("status", { + type: "set", + members: ["Success", "Fail", "Partial Success"] +}); - var configObj = { - rowSelection: true, - fieldCaching: true, - RTK: rtk, - columns: [ - { - field: "X_RIC_NAME", - name: "RIC", - tickColor: "CF_NETCHNG", - minWidth: 100, - editableContent: true - }, - { - field: "CF_TICK", - name: "Tick", - binding: onTickBinding, - }, - { - field: "CF_LAST", - tickColor: "CF_TICK", - blinking: true, - }, - { - field: "CF_NETCHNG", - blinking: true, - tickColor: "CF_TICK" - }, - { - field: "PCTCHNG", - heatmap: true, - formatType: "percent", - } - ], - rows: [ - { ric: "BA.N" }, - { ric: "AAPL.O" }, - { ric: "MSFT.O" }, - { ric: "TSLA.O" }, - { ric: "PTT.BK" }, - { ric: "AOT.BK" }, - { ric: ".DJI", asChain: true, collapsed: false }, - ], - extensions: [heatMapExt, textFormattingExt, contextMenuExt, rowColoringExt, inCellEditingExt, rowSelectionExt], - contextMenu: contextMenuModel, - inCellEditing: { - editableTitle: true, - editableContent: false, - autoSuggest: autoSuggest - }, - }; - - grid.config = configObj; - } +DataGenerator.addFieldInfo("jobName", { + type: "set", + members: [ + "Docs_Conv_021123_2", + "UPLD_Documents_031123_3", + "ConvUpld_Files_041123_1", + "Upload_Batch_051123_4", + "Files_Upld_061123_5", + "Upld_Conversion_071123", + "Documents_Upload_081123_1", + "Conv_Uploads_091123_2", + "Upload_Files_101123_3", + "Upld_Doc_111123_4", + "Conversion_Upload_121123_5", + "Uploads_Docs_131123_1", + "Docs_Conversion_141123_2", + "Upld_Batch_151123_3", + "Conversion_Batch_161123_4", + "Batch_Upload_171123_5", + "Upld_Documents_181123_1", + "Upload_Conv_191123_2", + "Conversion_Docs_201123_3", + "Upld_Files_211123_4" + ] +}); - function onTickBinding(e) { - var cell = e.cell; - var data = e.data; - var content = cell.getContent(); - if (!content) { - content = document.createElement("ef-icon"); +var rowSelection = new RowSelection(); +var inCellEditing = new InCellEditing(); +var rowFiltering = new RowFiltering(); +// Extensions +var fields = ["jobName", "status"]; +var records = DataGenerator.generateRecords(fields, { numRows: 50, seed: 0 }); +var config1 = { + columns: [ + { + title: "Job Name", + field: fields[0], + editableContent: true + }, + { + title: "Status", + field: fields[1], + width: 100 + }, + { + name: "Action", field: fields[1], + width: 150, + titleAlignment: "center", + binding: onActionBinding } - if (data != null) { + ], + staticDataRows: records, + rowFiltering: { + iconActivation: "onHover" + }, + extensions: [rowSelection, inCellEditing, rowFiltering] +}; - var dataColor = {}; - if (data === 2) { - dataColor.icon = "arrow-down-fill"; - dataColor.color = "rgb(245, 71, 91)"; - } else if (data == 1) { - dataColor.icon = "arrow-up-fill"; - dataColor.color = "rgb(57, 196, 110)"; - } - content.icon = dataColor.icon; - content.style.color = dataColor.color; - } - cell.setContent(content); - }; +function onActionBinding(e) { + var data = e.data; + var cell = e.cell; + var content = cell.getContent(); + if (!content) { + content = document.createElement("div"); - var autoSuggest = (window.autoSuggest = document.createElement( - "atlas-autosuggest" - )); - autoSuggest.moreSearchDisabled = true; // Disable more search result, if you want to enable it follow https://amp.int.refinitiv.com/#/package/@elf/atlas-autosuggest + var editIcon = document.createElement("ef-icon"); + editIcon.icon = "edit"; + editIcon.style.cursor = "pointer"; + editIcon.style.verticalAlign = "middle"; + editIcon.addEventListener("click", onEditClicked); - // ========== MOCK data server. Don't copy this section ================= - const flattenResponse = (response) => { - const { result, search, header, action } = response; - const suggestions = []; - const meta = { - url: search, - keyword: header.request.query - }; - if (result && result.length) { - result.forEach(row => { - const rowAsDefault = row.default === true; - const rowHits = row.hits; - if (rowHits && rowHits.length) { - rowHits.forEach((rowHit, hitIdx) => { - suggestions.push({ - label: rowHit.cmd, - value: rowHit, - highlighted: rowAsDefault && hitIdx === 0, - meta - }); - const relations = rowHit.relations; - if (relations) { - Object.keys(relations).forEach(key => { - const relation = relations[key]; - const relationAsDefault = relation.default === true; - const relationHits = relation.hits; - if (relationHits && relationHits.length) { - relationHits.forEach((relationHit, relationHitIdx) => { - suggestions.push({ - label: relationHit.cmd, - value: relationHit, - parent: rowHit, - asSub: true, - highlighted: relationAsDefault && relationHitIdx === 0, - meta - }); - }); - } - }); - } - }); - } - }); - } - return { - header, - meta, - suggestions, - action, - searchUrl: search - }; - }; - autoSuggest.addEventListener("suggestions-fetch-requested", suggest); - function suggest(ev) { - // Stop default data fetching + var deleteIcon = document.createElement("ef-icon"); + deleteIcon.icon = "trash"; + deleteIcon.style.cursor = "pointer"; + deleteIcon.style.verticalAlign = "middle"; + deleteIcon.addEventListener("click", onRemoveClicked); + + var runButton = document.createElement("ef-button"); + runButton.textContent = "Run"; + runButton.style.verticalAlign = "middle"; + runButton.addEventListener("click", onRunClicked); - ev.preventDefault(); + content.appendChild(editIcon); + content.appendChild(deleteIcon); + content.appendChild(runButton); + } + cell.setContent(content); +} - // construct cache key off the query object - var cacheKey = JSON.stringify(ev.detail.query); +function onRunClicked(e) { + var button = e.currentTarget; + var pos = grid.api.getRelativePosition(e); + var rowIndex = pos.rowIndex; + alert("Click :" + rowIndex); +} +function onRemoveClicked(e) { + var button = e.currentTarget; + var pos = grid.api.getRelativePosition(e); + var rowIndex = pos.rowIndex; + grid.api.removeRow(rowIndex); +} +function onEditClicked(e) { + var button = e.currentTarget; + var pos = grid.api.getRelativePosition(e); + var rowIndex = + pos.rowIndex; + inCellEditing.openEditor(0, rowIndex); +} - // (optional) use util to parse response - var responseData = { - "header": { - "request": { - "filter": "", - "highlight": true, - "userProfileAssetClass": "CSH", - "api-key": "czZTQ5MjY4", - "eikon_version": "Eikon Web", - "profile": "AlertsUI2", - "query": "IBV", - "uuid": "PATESTCPA724", - "appl_category": [] - }, - "response": { - "duration": 57, - "server": "c962fkkaswb04.int.thomsonreuters.com", - "num_results": 10 - } - }, - "result": [ - { - "name": "Equities", - "hits": [ - { - "score": 6867489, - "navigation": null, - "id": "1097326", - "title": "International Business Vehicle Corp", - "subtitle": "Ordinary Share - NYSE Consolidated - IBV", - "symbol": "" + "<b>" + ev.detail.query + "</b>" + "", - "cmd": "IBV", - "relations": {}, - "position": 0, - "source": "12", - "explanation": null, - "p": { - "RIC": "IBV", - "IsChain": false, - "PermID": "55839165994", - "OAPermID": "4295904307" - }, - "ac": [ - "A:1", - "A:1L" - ], - "s": "IBV", - "vc": "EQ", - "fr": false, - "st": "RIC", - "preview": true - }, - { - "score": 2762007, - "navigation": null, - "id": "131770829", - "title": "International Business Vehicle Corp", - "subtitle": "Ordinary Share - MiFID Composite Cross Market Service - IBV", - "symbol": "" + "<b>" + ev.detail.query + "</b>" + "IUSD.xbo", - "cmd": "IBVIUSD.xbo", - "relations": {}, - "position": 1, - "source": "12", - "explanation": null, - "p": { - "RIC": "IBVIUSD.xbo", - "IsChain": false, - "PermID": "21523029548", - "OAPermID": "4295904307" - }, - "ac": [ - "A:1", - "A:1L" - ], - "s": "IBVIUSD.xbo", - "vc": "EQ", - "fr": false, - "st": "RIC", - "preview": true - } - ], - "hasMore": true, - "default": false, - "size": 2, - "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllEquities&Search.Value=ibV" - }, - { - "name": "Portfolios & Lists", - "hits": [ - { - "score": 2952687, - "navigation": null, - "id": "599195610", - "title": "nam123", - "subtitle": "", - "symbol": "nam123", - "cmd": "nam123", - "relations": {}, - "position": 2, - "source": "62", - "explanation": null, - "p": { - "t": "FundedPortfolio" - }, - "s": "599195610", - "vc": "PORT", - "fr": false, - "st": "PortfolioID", - "preview": false - }, - { - "score": 2932687, - "navigation": null, - "id": "215781232", - "title": "BILL SHARE_AA IBV T", - "subtitle": "", - "symbol": "BILL SHARE_AA " + "<b>" + ev.detail.query + "</b>" + " T", - "cmd": "BILL SHARE_AA IBV T", - "relations": {}, - "position": 3, - "source": "62", - "explanation": null, - "p": { - "t": "FundedPortfolio" - }, - "s": "215781232", - "vc": "PORT", - "fr": false, - "st": "PortfolioID", - "preview": false - } - ], - "hasMore": true, - "default": false, - "size": 2, - "moreLink": "cpurl://views.cp./Explorer/SRCHxPORTF.aspx?Search.Value=ibV" - }, - { - "name": "Funds", - "hits": [ - { - "score": 2741047, - "navigation": null, - "id": "298223588", - "title": "iShares iBonds Dec 2024 Term Muni Bond ETF", - "subtitle": "Bond ETF - US123712312 - USD - Cboe Consolidated - IBVM", - "symbol": "" + "<b>" + ev.detail.query + "</b>" + "M.K", - "cmd": "IBVM.K", - "relations": {}, - "position": 4, - "source": "24", - "explanation": null, - "p": { - "RIC": "IBVM.K", - "IsChain": false, - "PermID": "21642135445", - "lipperId": "40215430" - }, - "ac": [ - "A:5", - "A:2X", - "A:L0", - "A:7", - "A:GL" - ], - "s": "IBVM.K", - "vc": "FND", - "fr": false, - "st": "RIC", - "preview": true - } - ], - "hasMore": true, - "default": false, - "size": 1, - "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllFunds&Search.Value=ibV" - }, - { - "name": "Options", - "hits": [ - { - "score": 2157436, - "navigation": null, - "id": "585064349", - "title": "OPRA International Business Vehicle Equity Option 145 Call Oct 2022 - IBV", - "subtitle": "Equity Cash Option - OPRA - IBVJ2122C145000", - "symbol": "" + "<b>" + ev.detail.query + "</b>" + "J212214500.U", - "cmd": "IBVJ212214500.U", - "relations": {}, - "position": 5, - "source": "14", - "explanation": null, - "p": { - "RIC": "IBVJ212214500.U", - "IsChain": false, - "PermID": "21873654768" - }, - "ac": [ - "A:1", - "A:2K", - "A:1T", - "A:7", - "A:G1", - "A:60" - ], - "s": "IBVJ212214500.U", - "vc": "OPT", - "fr": false, - "st": "RIC", - "preview": false - } - ], - "hasMore": true, - "default": false, - "size": 1, - "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllOptions&Search.Value=ibV" - }, - { - "name": "Indices", - "hits": [ - { - "score": 2157150, - "navigation": null, - "id": "215781470", - "title": "INTL BUSINES Single Stock Dividend", - "subtitle": "Equity Index", - "symbol": "0#.IBVDIV", - "cmd": "0#.IBVDIV", - "relations": {}, - "position": 6, - "source": "7", - "explanation": null, - "p": { - "RIC": "0#.IBVDIV", - "OAPermID": "4298427948" - }, - "ac": [ - "M:D6", - "I:M", - "I:17", - "A:1" - ], - "s": "0#.IBVDIV", - "vc": "INDX", - "fr": false, - "st": "RIC", - "preview": true - } - ], - "hasMore": true, - "default": false, - "size": 1, - "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllIndices&Search.Value=ibV" - }, - { - "name": "Commodities", - "hits": [ - { - "score": 1598945, - "navigation": null, - "id": "606788540", - "title": "Argus Ice Brent Month 2 Snapshot PA5000637", - "subtitle": "Crude Oil - Commodity Spot - ARGUS", - "symbol": "" + "<b>" + ev.detail.query + "</b>" + "SST=ARG", - "cmd": "IBVSST=ARG", - "relations": {}, - "position": 7, - "source": "15", - "explanation": null, - "p": { - "RIC": "IBVSST=ARG", - "IsChain": false, - "PermID": "21891574387" - }, - "ac": [ - "A:4", - "A:1Q" - ], - "s": "IBVSST=ARG", - "vc": "COM", - "fr": false, - "st": "RIC", - "preview": true - } - ], - "hasMore": true, - "default": false, - "size": 1, - "moreLink": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV" - }, - { - "name": "Fixed Income", - "hits": [ - { - "score": 1465259, - "navigation": null, - "id": "0x00102c80bf6b046c", - "title": "International Business Vehicle Corp - " + "<b>" + ev.detail.query + "</b>" + " 2.875% 09-Nov-2022", - "subtitle": "Plain Vanilla Fixed Coupon Bond - Underwritten", - "symbol": "US459200JC60", - "cmd": "US459200JC60", - "relations": {}, - "position": 8, - "source": "3", - "explanation": null, - "p": { - "RIC": "459200JC6=", - "OAPermID": "4295904307" - }, - "ac": [ - "A:2", - "A:J" - ], - "s": "459200JC6=", - "vc": "BOND", - "fr": false, - "st": "RIC", - "preview": true - } - ], - "hasMore": true, - "default": false, - "size": 1, - "moreLink": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV" - }, - { - "name": "FX", - "hits": [ - { - "score": 237124, - "navigation": null, - "id": "47051538460", - "title": "US Dollar/Chinese Renminbi 6 Month FX Forecast", - "subtitle": "IBV INDIA - 6 Month", - "symbol": "CNY6MP=0631", - "cmd": "CNY6MP=0631", - "relations": {}, - "position": 9, - "source": "23", - "explanation": null, - "p": { - "RIC": "CNY6MP=0631", - "PermID": "47051538460" - }, - "ac": [ - "M:D6", - "A:55", - "A:3", - "A:9", - "M:1MN" - ], - "s": "CNY6MP=0631", - "vc": "FX", - "fr": false, - "st": "RIC", - "preview": false - } - ], - "hasMore": true, - "default": false, - "size": 1, - "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllFXMoney&Search.Value=ibV" - } - ], - "search": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV", - "action": "\"IBV\" SRCH", - "assetClassifierStatus": "NOT_INVOKED", - "assetClassifierExplanation": "Current profile is not in the list of the silent mode profiles for asset classifier." - }; - var parsed = flattenResponse(responseData); +var grid = window.grid = document.getElementById("grid"); +grid.config = config1; - // cache the response - autoSuggest.cacheModel.set(cacheKey, parsed); +var searchInput = document.getElementById("search_input"); +searchInput.addEventListener("keyup", function (e) { + var input = e.currentTarget; + if (input._prevValue !== input.value) { + input._prevValue = input.value; + rowFiltering.refresh(); // Force filter triggering + } +}); - // set suggestions data - autoSuggest.setSuggestions(parsed); +function filterFunc(rowData, rowId, context) { + var str = ""; + var val = context.input.value.toLowerCase(); + for (var key in rowData) { + str += rowData[key] + " "; } - // ========== End mock data server section ====================================== + return str.toLowerCase().indexOf(val) > -1; +}; + +var context = { + input: searchInput +}; +rowFiltering.addGridFilter(filterFunc, context);
-

In the example above, we use MockRTK to mimic real-time data from the server. In this case, we have the ability to select a row to highlight it. Right-clicking on the row brings up a menu where you can insert or delete the row.

-

Furthermore, we have both regular RIC and chain RIC. They automatically add children to their respective rows. Additionally, there's a heat map extension that visually represents the data values. This visualization helps to decide when to make trades based on a midpoint.

+

In the example above, we show how to create a grid for managing data. This grid lets users filter, add, edit, and remove data in the grid itself. We used three main features: row filtering, in cell editing, and row selection.

+

Row filtering lets users type in a box to search and filter data across all columns in the grid. Row selection allows users to pick one or more rows in the grid.

+

In cell editing is about changing the data in the grid directly. For our example, we changed the "Job Name" using this feature.

diff --git a/template-140.html b/template-140.html index 6bc99853..9c6441f9 100644 --- a/template-140.html +++ b/template-140.html @@ -1,60 +1,17 @@ -

Custom Sort Logic

-

There are several cases where the data stored in each field in the data model is not a primitive type. Sorting this data requires a special approach with custom sorting logic.

-
-

Note: comparison functions receive the same argument as Array.prototype.sort.

-
-

To set custom sort logic for each column, do the following:

-
var config = {
-    // any other grid's options
-    columns: [
-        { name: "Column 1", field: "field1", sortLogic: function(a, b, order) {/* Some compare function */} },
-        { name: "Column 2", field: "field2" },
-    ],
+

Realtime Data

+
body {
+    padding: 24px;
 }
-
-

The callback will also receive extra information about the column being sorted from the fourth parameter.

-
var myCustomSorting = function(valA, valB, order, contextObj) {
-    // contextObj provide more information about the column being sorted such as colIndex and field
-    // ...
-    return valA - valB;
-};
 
-var config = {
-    // any other grid's options
-    columns: [
-        { name: "Column 1", field: "field1", sortLogic: myCustomSorting},
-        { name: "Column 2", field: "field2" },
-    ],
+efx-grid {
+    height: 300px;
 }
-
-

You can enable rowSorting to use RowDefinition object for sorting comparison. This is useful when we want to compare data other than the data from the column being sorted.

-
var myCustomSorting = function(rowDefA, rowDefB, order, contextObj) {
-    // Now we can access any data within a row from the RowDefinition object
-    var valA = rowDefA.getData(contextObj.field);
-    var valB = rowDefB.getData(contextObj.field);
-    var extraInfoA = rowDefA.getData("some other field");
-    var extraInfoB = rowDefB.getData("some other field");
-    // ...
-    return number;
-};
 
-var config = {
-    // any other grid's options
-    columns: [
-        { name: "Column 1", field: "field1", rowSorting: true, sortLogic: myCustomSorting},
-        { name: "Column 2", field: "field2" },
-    ],
-}
-
-
-

For notRealTimeField column, the default comparison method is row sorting. If you still want to sort by data instead of RowDefinition object, set rowSorting to false to override the default behavior.

-
-

Example

-
efx-grid {
-    height: 300px;
+hr {
+    margin: 8px;
 }
 
-
<efx-grid></efx-grid>
+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -65,74 +22,570 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -function sortTextAsNumber(valA, valB, order, contextObj) { - var numA = +valA; // Convert string to number - var numB = Number(valB); // Another way to convert string to number - if(numA !== numA) { // Fastest way to check for NaN value - if(isNaN(numB)) { // Traditional and slower way to check for NaN value - return 0; - } else { - return 1; // Always put NaN value at the bottom - } - } else if(numB !== numB) { - return -1; // Always put NaN value at the bottom - } - if(numA < numB) { - return -order; - } - if(numB < numA) { - return order; +var heatMapExt = new HeatMap(); + var textFormattingExt = new TextFormatting(); + var contextMenuExt = new ContextMenu(); + var rowColoringExt = new RowColoring(); + var inCellEditingExt = new InCellEditing(); + var rowSelectionExt = new RowSelection(); + + var grid = document.getElementById("grid"); + var Toolkit = tr.MockRTK ? tr.MockRTK : MockRTK; + Toolkit.init({ ID: 'rtk-efx-grid', minInterval: 100, maxInterval: 800 }, ['Quotes', 'Data']).then(onInit); + function onInit(rtk) { + const contextMenuModel = { + items: { + INSERT_ROW: { + text: "Insert Row", + callback: function (e) { + var rowIndex = e.rowIndex; + grid.api.insertRow({}, rowIndex); + inCellEditingExt.openEditor(0, rowIndex); + } + }, + REMOVE_ROW: { + text: "Remove Row", + callback: function (e) { + var selectionRows = rowSelectionExt.getSelectedRows(); + grid.api.removeRows(selectionRows); + } + } + }, + onMenu: function (e) { + var context = e.context; + var menu = e.menu; + var rowIndex = e.rowIndex; + if (context === "content") { + if (grid.api.getRowDefinition(rowIndex).getType() !== "CONSTITUENT") { + menu.addItems(["INSERT_ROW", "REMOVE_ROW"]); + } else { + menu.addItems(["INSERT_ROW"]); + } + } + } + }; + + var configObj = { + rowSelection: true, + fieldCaching: true, + RTK: rtk, + columns: [ + { + field: "X_RIC_NAME", + name: "RIC", + tickColor: "CF_NETCHNG", + minWidth: 100, + editableContent: true + }, + { + field: "CF_TICK", + name: "Tick", + binding: onTickBinding, + }, + { + field: "CF_LAST", + tickColor: "CF_TICK", + blinking: true, + }, + { + field: "CF_NETCHNG", + blinking: true, + tickColor: "CF_TICK" + }, + { + field: "PCTCHNG", + heatmap: true, + formatType: "percent", + } + ], + rows: [ + { ric: "BA.N" }, + { ric: "AAPL.O" }, + { ric: "MSFT.O" }, + { ric: "TSLA.O" }, + { ric: "PTT.BK" }, + { ric: "AOT.BK" }, + { ric: ".DJI", asChain: true, collapsed: false }, + ], + extensions: [heatMapExt, textFormattingExt, contextMenuExt, rowColoringExt, inCellEditingExt, rowSelectionExt], + contextMenu: contextMenuModel, + inCellEditing: { + editableTitle: true, + editableContent: false, + autoSuggest: autoSuggest + }, + }; + + grid.config = configObj; } - - return 0; -} -// Initial data set -var records = [ - { col1: "A", num1: 40, text: "100" }, - { col1: "B", num1: 22, text: "200" }, - { col1: "C", num1: 55, text: "-10" }, - { col1: "D", num1: 11, text: "This is Text" }, - { col1: "E", num1: 33, text: "120" }, - { col1: "F", num1: 66, text: "-20" }, - { col1: "G", num1: 44, text: "N/A" }, - { col1: "H", num1: 22, text: "110" }, - { col1: "I", num1: 11, text: "240" }, - { col1: "J", num1: 10, text: "100" } -]; -var configObj = { - sorting: { - multiColumn: true, - threeStatesSorting: true - }, - columns: [ - { - name: "Column 1", - field: "col1", - width: 100 - }, - { - name: "Default Sorting", - field: "num1", - textAlign: "right" - }, - { - name: "Custom Sorting", - field: "text", - sortingLogic: sortTextAsNumber - }, - { - name: "Not Sortable", - field: "Some Field", - sortable: false, - width: 150 + function onTickBinding(e) { + var cell = e.cell; + var data = e.data; + var content = cell.getContent(); + if (!content) { + content = document.createElement("ef-icon"); + } + if (data != null) { + + var dataColor = {}; + if (data === 2) { + dataColor.icon = "arrow-down-fill"; + dataColor.color = "rgb(245, 71, 91)"; + } else if (data == 1) { + dataColor.icon = "arrow-up-fill"; + dataColor.color = "rgb(57, 196, 110)"; + } + content.icon = dataColor.icon; + content.style.color = dataColor.color; + } + cell.setContent(content); + }; + + var autoSuggest = (window.autoSuggest = document.createElement( + "efx-autosuggest" + )); + autoSuggest.moreSearchDisabled = true; // Disable more search result, if you want to enable it follow https://amp.int.refinitiv.com/#/package/@elf/efx-autosuggest + + // ========== MOCK data server. Don't copy this section ================= + const flattenResponse = (response) => { + const { result, search, header, action } = response; + const suggestions = []; + const meta = { + url: search, + keyword: header.request.query + }; + if (result && result.length) { + result.forEach(row => { + const rowAsDefault = row.default === true; + const rowHits = row.hits; + if (rowHits && rowHits.length) { + rowHits.forEach((rowHit, hitIdx) => { + suggestions.push({ + label: rowHit.cmd, + value: rowHit, + highlighted: rowAsDefault && hitIdx === 0, + meta + }); + const relations = rowHit.relations; + if (relations) { + Object.keys(relations).forEach(key => { + const relation = relations[key]; + const relationAsDefault = relation.default === true; + const relationHits = relation.hits; + if (relationHits && relationHits.length) { + relationHits.forEach((relationHit, relationHitIdx) => { + suggestions.push({ + label: relationHit.cmd, + value: relationHit, + parent: rowHit, + asSub: true, + highlighted: relationAsDefault && relationHitIdx === 0, + meta + }); + }); + } + }); + } + }); + } + }); } - ], - extensions: [], - staticDataRows: records -}; + return { + header, + meta, + suggestions, + action, + searchUrl: search + }; + }; + autoSuggest.addEventListener("suggestions-fetch-requested", suggest); + function suggest(ev) { + // Stop default data fetching -var grid = document.getElementsByTagName("efx-grid")[0]; -grid.config = configObj; + ev.preventDefault(); + + // construct cache key off the query object + var cacheKey = JSON.stringify(ev.detail.query); + + // (optional) use util to parse response + var responseData = { + "header": { + "request": { + "filter": "", + "highlight": true, + "userProfileAssetClass": "CSH", + "api-key": "czZTQ5MjY4", + "eikon_version": "Eikon Web", + "profile": "AlertsUI2", + "query": "IBV", + "uuid": "PATESTCPA724", + "appl_category": [] + }, + "response": { + "duration": 57, + "server": "c962fkkaswb04.int.thomsonreuters.com", + "num_results": 10 + } + }, + "result": [ + { + "name": "Equities", + "hits": [ + { + "score": 6867489, + "navigation": null, + "id": "1097326", + "title": "International Business Vehicle Corp", + "subtitle": "Ordinary Share - NYSE Consolidated - IBV", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "", + "cmd": "IBV", + "relations": {}, + "position": 0, + "source": "12", + "explanation": null, + "p": { + "RIC": "IBV", + "IsChain": false, + "PermID": "55839165994", + "OAPermID": "4295904307" + }, + "ac": [ + "A:1", + "A:1L" + ], + "s": "IBV", + "vc": "EQ", + "fr": false, + "st": "RIC", + "preview": true + }, + { + "score": 2762007, + "navigation": null, + "id": "131770829", + "title": "International Business Vehicle Corp", + "subtitle": "Ordinary Share - MiFID Composite Cross Market Service - IBV", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "IUSD.xbo", + "cmd": "IBVIUSD.xbo", + "relations": {}, + "position": 1, + "source": "12", + "explanation": null, + "p": { + "RIC": "IBVIUSD.xbo", + "IsChain": false, + "PermID": "21523029548", + "OAPermID": "4295904307" + }, + "ac": [ + "A:1", + "A:1L" + ], + "s": "IBVIUSD.xbo", + "vc": "EQ", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 2, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllEquities&Search.Value=ibV" + }, + { + "name": "Portfolios & Lists", + "hits": [ + { + "score": 2952687, + "navigation": null, + "id": "599195610", + "title": "nam123", + "subtitle": "", + "symbol": "nam123", + "cmd": "nam123", + "relations": {}, + "position": 2, + "source": "62", + "explanation": null, + "p": { + "t": "FundedPortfolio" + }, + "s": "599195610", + "vc": "PORT", + "fr": false, + "st": "PortfolioID", + "preview": false + }, + { + "score": 2932687, + "navigation": null, + "id": "215781232", + "title": "BILL SHARE_AA IBV T", + "subtitle": "", + "symbol": "BILL SHARE_AA " + "<b>" + ev.detail.query + "</b>" + " T", + "cmd": "BILL SHARE_AA IBV T", + "relations": {}, + "position": 3, + "source": "62", + "explanation": null, + "p": { + "t": "FundedPortfolio" + }, + "s": "215781232", + "vc": "PORT", + "fr": false, + "st": "PortfolioID", + "preview": false + } + ], + "hasMore": true, + "default": false, + "size": 2, + "moreLink": "cpurl://views.cp./Explorer/SRCHxPORTF.aspx?Search.Value=ibV" + }, + { + "name": "Funds", + "hits": [ + { + "score": 2741047, + "navigation": null, + "id": "298223588", + "title": "iShares iBonds Dec 2024 Term Muni Bond ETF", + "subtitle": "Bond ETF - US123712312 - USD - Cboe Consolidated - IBVM", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "M.K", + "cmd": "IBVM.K", + "relations": {}, + "position": 4, + "source": "24", + "explanation": null, + "p": { + "RIC": "IBVM.K", + "IsChain": false, + "PermID": "21642135445", + "lipperId": "40215430" + }, + "ac": [ + "A:5", + "A:2X", + "A:L0", + "A:7", + "A:GL" + ], + "s": "IBVM.K", + "vc": "FND", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllFunds&Search.Value=ibV" + }, + { + "name": "Options", + "hits": [ + { + "score": 2157436, + "navigation": null, + "id": "585064349", + "title": "OPRA International Business Vehicle Equity Option 145 Call Oct 2022 - IBV", + "subtitle": "Equity Cash Option - OPRA - IBVJ2122C145000", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "J212214500.U", + "cmd": "IBVJ212214500.U", + "relations": {}, + "position": 5, + "source": "14", + "explanation": null, + "p": { + "RIC": "IBVJ212214500.U", + "IsChain": false, + "PermID": "21873654768" + }, + "ac": [ + "A:1", + "A:2K", + "A:1T", + "A:7", + "A:G1", + "A:60" + ], + "s": "IBVJ212214500.U", + "vc": "OPT", + "fr": false, + "st": "RIC", + "preview": false + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllOptions&Search.Value=ibV" + }, + { + "name": "Indices", + "hits": [ + { + "score": 2157150, + "navigation": null, + "id": "215781470", + "title": "INTL BUSINES Single Stock Dividend", + "subtitle": "Equity Index", + "symbol": "0#.IBVDIV", + "cmd": "0#.IBVDIV", + "relations": {}, + "position": 6, + "source": "7", + "explanation": null, + "p": { + "RIC": "0#.IBVDIV", + "OAPermID": "4298427948" + }, + "ac": [ + "M:D6", + "I:M", + "I:17", + "A:1" + ], + "s": "0#.IBVDIV", + "vc": "INDX", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllIndices&Search.Value=ibV" + }, + { + "name": "Commodities", + "hits": [ + { + "score": 1598945, + "navigation": null, + "id": "606788540", + "title": "Argus Ice Brent Month 2 Snapshot PA5000637", + "subtitle": "Crude Oil - Commodity Spot - ARGUS", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "SST=ARG", + "cmd": "IBVSST=ARG", + "relations": {}, + "position": 7, + "source": "15", + "explanation": null, + "p": { + "RIC": "IBVSST=ARG", + "IsChain": false, + "PermID": "21891574387" + }, + "ac": [ + "A:4", + "A:1Q" + ], + "s": "IBVSST=ARG", + "vc": "COM", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV" + }, + { + "name": "Fixed Income", + "hits": [ + { + "score": 1465259, + "navigation": null, + "id": "0x00102c80bf6b046c", + "title": "International Business Vehicle Corp - " + "<b>" + ev.detail.query + "</b>" + " 2.875% 09-Nov-2022", + "subtitle": "Plain Vanilla Fixed Coupon Bond - Underwritten", + "symbol": "US459200JC60", + "cmd": "US459200JC60", + "relations": {}, + "position": 8, + "source": "3", + "explanation": null, + "p": { + "RIC": "459200JC6=", + "OAPermID": "4295904307" + }, + "ac": [ + "A:2", + "A:J" + ], + "s": "459200JC6=", + "vc": "BOND", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV" + }, + { + "name": "FX", + "hits": [ + { + "score": 237124, + "navigation": null, + "id": "47051538460", + "title": "US Dollar/Chinese Renminbi 6 Month FX Forecast", + "subtitle": "IBV INDIA - 6 Month", + "symbol": "CNY6MP=0631", + "cmd": "CNY6MP=0631", + "relations": {}, + "position": 9, + "source": "23", + "explanation": null, + "p": { + "RIC": "CNY6MP=0631", + "PermID": "47051538460" + }, + "ac": [ + "M:D6", + "A:55", + "A:3", + "A:9", + "M:1MN" + ], + "s": "CNY6MP=0631", + "vc": "FX", + "fr": false, + "st": "RIC", + "preview": false + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllFXMoney&Search.Value=ibV" + } + ], + "search": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV", + "action": "\"IBV\" SRCH", + "assetClassifierStatus": "NOT_INVOKED", + "assetClassifierExplanation": "Current profile is not in the list of the silent mode profiles for asset classifier." + }; + var parsed = flattenResponse(responseData); + + // cache the response + autoSuggest.cacheModel.set(cacheKey, parsed); + + // set suggestions data + autoSuggest.setSuggestions(parsed); + } + // ========== End mock data server section ======================================
- \ No newline at end of file +

In the example above, we use MockRTK to mimic real-time data from the server. In this case, we have the ability to select a row to highlight it. Right-clicking on the row brings up a menu where you can insert or delete the row.

+

Furthermore, we have both regular RIC and chain RIC. They automatically add children to their respective rows. Additionally, there's a heat map extension that visually represents the data values. This visualization helps to decide when to make trades based on a midpoint.

diff --git a/template-141.html b/template-141.html index d30e9f53..6bc99853 100644 --- a/template-141.html +++ b/template-141.html @@ -1,29 +1,60 @@ -

Default Sort

-

You can sort data in the grid automatically after initialization by specifying the initialSort option, which receives the following two options: colIndex and sortOrder.

-

The possible values of sortOrder are:

-
    -
  • a for Ascending
  • -
  • d for Descending
  • -
  • n for Neutral
  • -
-

You can see all possible values for the sort order here.

+

Custom Sort Logic

+

There are several cases where the data stored in each field in the data model is not a primitive type. Sorting this data requires a special approach with custom sorting logic.

+
+

Note: comparison functions receive the same argument as Array.prototype.sort.

+
+

To set custom sort logic for each column, do the following:

var config = {
     // any other grid's options
-    sorting: {
-        sortableColumns: true,
-        initialSort: {
-            colIndex: 0,
-            sortOrder: "d"
-        }
-    }
+    columns: [
+        { name: "Column 1", field: "field1", sortLogic: function(a, b, order) {/* Some compare function */} },
+        { name: "Column 2", field: "field2" },
+    ],
+}
+
+

The callback will also receive extra information about the column being sorted from the fourth parameter.

+
var myCustomSorting = function(valA, valB, order, contextObj) {
+    // contextObj provide more information about the column being sorted such as colIndex and field
+    // ...
+    return valA - valB;
+};
+
+var config = {
+    // any other grid's options
+    columns: [
+        { name: "Column 1", field: "field1", sortLogic: myCustomSorting},
+        { name: "Column 2", field: "field2" },
+    ],
 }
 
+

You can enable rowSorting to use RowDefinition object for sorting comparison. This is useful when we want to compare data other than the data from the column being sorted.

+
var myCustomSorting = function(rowDefA, rowDefB, order, contextObj) {
+    // Now we can access any data within a row from the RowDefinition object
+    var valA = rowDefA.getData(contextObj.field);
+    var valB = rowDefB.getData(contextObj.field);
+    var extraInfoA = rowDefA.getData("some other field");
+    var extraInfoB = rowDefB.getData("some other field");
+    // ...
+    return number;
+};
+
+var config = {
+    // any other grid's options
+    columns: [
+        { name: "Column 1", field: "field1", rowSorting: true, sortLogic: myCustomSorting},
+        { name: "Column 2", field: "field2" },
+    ],
+}
+
+
+

For notRealTimeField column, the default comparison method is row sorting. If you still want to sort by data instead of RowDefinition object, set rowSorting to false to override the default behavior.

+

Example

-
efx-grid {
-    height: 200px;
+
efx-grid {
+    height: 300px;
 }
 
-
<efx-grid id="grid"></efx-grid>
+
<efx-grid></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -34,27 +65,74 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); +function sortTextAsNumber(valA, valB, order, contextObj) { + var numA = +valA; // Convert string to number + var numB = Number(valB); // Another way to convert string to number + if(numA !== numA) { // Fastest way to check for NaN value + if(isNaN(numB)) { // Traditional and slower way to check for NaN value + return 0; + } else { + return 1; // Always put NaN value at the bottom + } + } else if(numB !== numB) { + return -1; // Always put NaN value at the bottom + } + if(numA < numB) { + return -order; + } + if(numB < numA) { + return order; + } + + return 0; +} + +// Initial data set +var records = [ + { col1: "A", num1: 40, text: "100" }, + { col1: "B", num1: 22, text: "200" }, + { col1: "C", num1: 55, text: "-10" }, + { col1: "D", num1: 11, text: "This is Text" }, + { col1: "E", num1: 33, text: "120" }, + { col1: "F", num1: 66, text: "-20" }, + { col1: "G", num1: 44, text: "N/A" }, + { col1: "H", num1: 22, text: "110" }, + { col1: "I", num1: 11, text: "240" }, + { col1: "J", num1: 10, text: "100" } +]; var configObj = { sorting: { - sortableColumns: true, - initialSort: { - colIndex: 0, // Column index - sortOrder: "d" - } + multiColumn: true, + threeStatesSorting: true }, columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 120}, - {name: "Last", field: fields[2], width: 100}, - {name: "Net. Chng", field: fields[3], width: 100}, - {name: "Industry", field: fields[4]} + { + name: "Column 1", + field: "col1", + width: 100 + }, + { + name: "Default Sorting", + field: "num1", + textAlign: "right" + }, + { + name: "Custom Sorting", + field: "text", + sortingLogic: sortTextAsNumber + }, + { + name: "Not Sortable", + field: "Some Field", + sortable: false, + width: 150 + } ], + extensions: [], staticDataRows: records }; -var grid = document.getElementById("grid"); +var grid = document.getElementsByTagName("efx-grid")[0]; grid.config = configObj;
\ No newline at end of file diff --git a/template-142.html b/template-142.html index 7a28e535..d30e9f53 100644 --- a/template-142.html +++ b/template-142.html @@ -1,53 +1,26 @@ -

Multi-column/three-state sorting

-

Sorting can be done on several columns together. You need to add the sorting property with two sub-properties: multiColumn and threeStateSorting.

-

The property threeStatesSorting allows the column to be reset to the neutral state at every third click. Turning on threeStatesSorting makes multi-column sorting easier to use.

-
var config = {
-    // ... other config
-    sorting: {
-        sortableColumns: true,
-        multiColumn: true, // The value can also be a maximum number of sorted columns 
-        threeStatesSorting: true
-    }
-}
-
-

Sort multiple columns at the initialization

-

It is possible to set the initial sort with multiColumn enabled. We can use initialSort to define an array of SortableTitlePlugin.InitialSort.

-
-

If multiColumn is not enabled, the initialSort will only take the first object of an array into consideration.

-
+

Default Sort

+

You can sort data in the grid automatically after initialization by specifying the initialSort option, which receives the following two options: colIndex and sortOrder.

+

The possible values of sortOrder are:

+
    +
  • a for Ascending
  • +
  • d for Descending
  • +
  • n for Neutral
  • +
+

You can see all possible values for the sort order here.

var config = {
     // any other grid's options
     sorting: {
         sortableColumns: true,
-        multiColumn: true,
-        initialSort: [{
+        initialSort: {
             colIndex: 0,
             sortOrder: "d"
-        }, {
-            colIndex: 1,
-            sortOrder: "d"
-        }]
+        }
     }
 }
 
-

Sort multiple columns at runtime

-

To change sorting states at runtime, use sortColumns from the built-in SortableTitlePlugin

-
var grid = document.getElementById("grid");
-var sort = grid.api.getCoreGrid().getPlugin("SortableTitle");
-sort.sortColumns([
-    {
-        colIndex: 0, // Column index 0 with order descending.
-        sortOrder: "d"
-    }, {
-        colIndex: 1, // Column index 1 with order descending
-        sortOrder: "d"
-    }
-]);
-
-

For all available options and APIs, please visit SortableTitlePlugin

Example

-
efx-grid {
-    height: 300px;
+
efx-grid {
+    height: 200px;
 }
 
<efx-grid id="grid"></efx-grid>
@@ -61,22 +34,22 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "group3", "boolean", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 15 }); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { sorting: { sortableColumns: true, - multiColumn: 3, // Maximum of 3 sorted columns at the same time - threeStatesSorting: true + initialSort: { + colIndex: 0, // Column index + sortOrder: "d" + } }, columns: [ {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 80}, - {name: "Group 1", field: fields[2], width: 80}, - {name: "Group 2", field: fields[3], width: 80}, - {name: "Last", field: fields[4], width: 80}, - {name: "Net. Chng", field: fields[5], width: 80}, - {name: "Industry", field: fields[6]} + {name: "Market", field: fields[1], width: 120}, + {name: "Last", field: fields[2], width: 100}, + {name: "Net. Chng", field: fields[3], width: 100}, + {name: "Industry", field: fields[4]} ], staticDataRows: records }; @@ -84,4 +57,4 @@

Example

var grid = document.getElementById("grid"); grid.config = configObj;
-




+ \ No newline at end of file diff --git a/template-143.html b/template-143.html index 7eebfe22..7a28e535 100644 --- a/template-143.html +++ b/template-143.html @@ -1,57 +1,56 @@ -

Server-side Sorting

-

In manual sorting mode, clicking on the column title will change the sorting status, but no actual sorting is done on the grid data.

-

One use case is, if you want to do server-side sorting, you can use manual sorting mode in conjunction with the columnSorted event and the XMLHttpRequest method.

-

To turn manual sorting on, set indicatorOnly to true.

+

Multi-column/three-state sorting

+

Sorting can be done on several columns together. You need to add the sorting property with two sub-properties: multiColumn and threeStateSorting.

+

The property threeStatesSorting allows the column to be reset to the neutral state at every third click. Turning on threeStatesSorting makes multi-column sorting easier to use.

var config = {
-    // any other grid's options
+    // ... other config
     sorting: {
         sortableColumns: true,
-        indicatorOnly: true
+        multiColumn: true, // The value can also be a maximum number of sorted columns 
+        threeStatesSorting: true
     }
 }
 
-

You also need to listen to columnSorted event in order to trigger server-side sorting. The event can be listened from the shortcut in sorting config or through the built-in plugin.

-
function onColumnSorted (evtArg) {
-    var sortingStates = grid.api.getSortingStates();
-    var sortingState = sortingStates[0];
-    var sortOrder = sortingState.order;
-    // At this point, you may request sorted data from the server.
-}
-
-var config = {
+

Sort multiple columns at the initialization

+

It is possible to set the initial sort with multiColumn enabled. We can use initialSort to define an array of SortableTitlePlugin.InitialSort.

+
+

If multiColumn is not enabled, the initialSort will only take the first object of an array into consideration.

+
+
var config = {
     // any other grid's options
     sorting: {
-        columnSorted: onColumnSorted
+        sortableColumns: true,
+        multiColumn: true,
+        initialSort: [{
+            colIndex: 0,
+            sortOrder: "d"
+        }, {
+            colIndex: 1,
+            sortOrder: "d"
+        }]
     }
-};
-
-// Alternatively you can listen to the event directly from the built-in plugin
-grid.addEventListener("configured", function(e) {
-    var core = e.detail.api.getCoreGrid();
-    var plugin = core.getPlugin("SortableTitle");
-    // plugin.listen("columnSorted", onColumnSorted);
-});
+}
+
+

Sort multiple columns at runtime

+

To change sorting states at runtime, use sortColumns from the built-in SortableTitlePlugin

+
var grid = document.getElementById("grid");
+var sort = grid.api.getCoreGrid().getPlugin("SortableTitle");
+sort.sortColumns([
+    {
+        colIndex: 0, // Column index 0 with order descending.
+        sortOrder: "d"
+    }, {
+        colIndex: 1, // Column index 1 with order descending
+        sortOrder: "d"
+    }
+]);
 
-

You can see all possible values for the sort order here.

+

For all available options and APIs, please visit SortableTitlePlugin

Example

-
html hr {
-    margin: 5px;
-}
-efx-grid {
-    height: 200px;
-}
-textarea {
-    width: 100%;
-    height: 50px;
-    margin-bottom: 30px;
+
efx-grid {
+    height: 300px;
 }
 
-
<button id="sort_btn1">Sort Column 1</button>
-<button id="sort_btn2">Sort Column 2</button>
-<hr>
-<efx-grid id="grid"></efx-grid>
-<hr>
-<textarea id="output_ta" placeholder="Click at the grid header to sort"></textarea>
+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -62,85 +61,27 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -document.getElementById("sort_btn1").addEventListener("click", function(e){ - grid.api.sortColumn(0); // Cycle through sorting sequence -}); -document.getElementById("sort_btn2").addEventListener("click", function(e){ - grid.api.sortColumn(1); // Cycle through sorting sequence -}); - -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); +var fields = ["companyName", "market", "group3", "boolean", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 15 }); var configObj = { sorting: { sortableColumns: true, - indicatorOnly: true, - columnSorted: function(evtArg) { - var core = grid.api.getCoreGrid(); - var plugin = core.getPlugin("SortableTitle"); - var objs = plugin.getSortedColumns(); - var obj = objs[0]; - var field = grid.api.getColumnField(obj.colIndex); - var sortOrder = (obj.sortOrder === "a") ? "ascending" : "decending"; - - var ta = document.getElementById("output_ta"); - ta.value = "Field " + field + " is sorted in " + sortOrder + " order\n" + ta.value; - - // At this point, you may request sorted data from the server. - requestData(evtArg); - } + multiColumn: 3, // Maximum of 3 sorted columns at the same time + threeStatesSorting: true }, columns: [ {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 120}, - {name: "Last", field: fields[2], width: 100}, - {name: "Net. Chng", field: fields[3], width: 100}, - {name: "Industry", field: fields[4]} + {name: "Market", field: fields[1], width: 80}, + {name: "Group 1", field: fields[2], width: 80}, + {name: "Group 2", field: fields[3], width: 80}, + {name: "Last", field: fields[4], width: 80}, + {name: "Net. Chng", field: fields[5], width: 80}, + {name: "Industry", field: fields[6]} ], staticDataRows: records }; - -function mockCallbackData(resp) { - if (resp.success) { - console.log("Loading success, Data sorted"); - grid.data = resp.data; - } -} - -// Mock to request data -function requestData(obj) { - console.log("Loading data from server side"); - // Mock data on server side - setTimeout(function () { - // Mock to query data from DB. - var resRecords = DataGenerator.generateRecords(fields, { numRows: 10 }); // NOTE: It's random data - var sortField = obj.sortedField; - var sortOrder = obj.sortOrder; - resRecords = resRecords.sort(sortFx.bind(null, sortOrder, sortField)); - mockCallbackData({ - success: true, - data: resRecords - }); - }, 100); -} - -function sortFx(sortOrder, sortField, rowA, rowB) { - return compareFunction(rowA, rowB, sortField, sortOrder); -} - -function compareFunction(rowA, rowB, sortField, sortOrder) { - var valueA = rowA[sortField]; - var valueB = rowB[sortField]; - - if (sortOrder === "a") { - return valueA < valueB ? -1 : valueA > valueB ? 1 : 0; - } else { - return valueA > valueB ? -1 : valueA < valueB ? 1 : 0; - } -} - var grid = document.getElementById("grid"); grid.config = configObj;
-



+




diff --git a/template-144.html b/template-144.html index b83db8ac..7eebfe22 100644 --- a/template-144.html +++ b/template-144.html @@ -1,26 +1,57 @@ -

Get Sorting States/Reset All

-

The getSortedColumns() method returns an array of the currently applied sorting states (with the colIndex and sortOrder properties).

-

Additionally, the clearSortState() method resets the current sorting states to their default neutral state.

-

A list of all sorting-related events can be found in the Events Handling section.

-
var sort = grid.api.getCoreGrid().getPlugin("SortableTitle");
-var states = sort.getSortedColumns(); // Return an array of the current active sorting states
+

Server-side Sorting

+

In manual sorting mode, clicking on the column title will change the sorting status, but no actual sorting is done on the grid data.

+

One use case is, if you want to do server-side sorting, you can use manual sorting mode in conjunction with the columnSorted event and the XMLHttpRequest method.

+

To turn manual sorting on, set indicatorOnly to true.

+
var config = {
+    // any other grid's options
+    sorting: {
+        sortableColumns: true,
+        indicatorOnly: true
+    }
+}
+
+

You also need to listen to columnSorted event in order to trigger server-side sorting. The event can be listened from the shortcut in sorting config or through the built-in plugin.

+
function onColumnSorted (evtArg) {
+    var sortingStates = grid.api.getSortingStates();
+    var sortingState = sortingStates[0];
+    var sortOrder = sortingState.order;
+    // At this point, you may request sorted data from the server.
+}
+
+var config = {
+    // any other grid's options
+    sorting: {
+        columnSorted: onColumnSorted
+    }
+};
 
-sort.clearSortState(); // Reset all sorting states to neutral
+// Alternatively you can listen to the event directly from the built-in plugin
+grid.addEventListener("configured", function(e) {
+    var core = e.detail.api.getCoreGrid();
+    var plugin = core.getPlugin("SortableTitle");
+    // plugin.listen("columnSorted", onColumnSorted);
+});
 
+

You can see all possible values for the sort order here.

Example

-
efx-grid {
+
html hr {
+    margin: 5px;
+}
+efx-grid {
     height: 200px;
 }
 textarea {
     width: 100%;
     height: 50px;
-    margin: 10px 0;
+    margin-bottom: 30px;
 }
 
-
<button id="get_btn">Get Current States</button>
-<button id="reset_btn">Clear All Sorting</button>
-<textarea id="output_ta" placeholder="Click at the grid header to sort"></textarea>
+
<button id="sort_btn1">Sort Column 1</button>
+<button id="sort_btn2">Sort Column 2</button>
+<hr>
 <efx-grid id="grid"></efx-grid>
+<hr>
+<textarea id="output_ta" placeholder="Click at the grid header to sort"></textarea>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -31,12 +62,33 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ +document.getElementById("sort_btn1").addEventListener("click", function(e){ + grid.api.sortColumn(0); // Cycle through sorting sequence +}); +document.getElementById("sort_btn2").addEventListener("click", function(e){ + grid.api.sortColumn(1); // Cycle through sorting sequence +}); + var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { sorting: { sortableColumns: true, - threeStatesSorting: true + indicatorOnly: true, + columnSorted: function(evtArg) { + var core = grid.api.getCoreGrid(); + var plugin = core.getPlugin("SortableTitle"); + var objs = plugin.getSortedColumns(); + var obj = objs[0]; + var field = grid.api.getColumnField(obj.colIndex); + var sortOrder = (obj.sortOrder === "a") ? "ascending" : "decending"; + + var ta = document.getElementById("output_ta"); + ta.value = "Field " + field + " is sorted in " + sortOrder + " order\n" + ta.value; + + // At this point, you may request sorted data from the server. + requestData(evtArg); + } }, columns: [ {name: "Company", field: fields[0]}, @@ -48,21 +100,47 @@

Example

staticDataRows: records }; -var grid = document.getElementById("grid"); -grid.config = configObj; -document.getElementById("get_btn").addEventListener("click", function() { - // Return an array of the current active sorting states - var sort = grid.api.getCoreGrid().getPlugin("SortableTitle"); - var states = sort.getSortedColumns(); +function mockCallbackData(resp) { + if (resp.success) { + console.log("Loading success, Data sorted"); + grid.data = resp.data; + } +} - var ta = document.getElementById('output_ta'); - ta.value = JSON.stringify(states, 2, null) + "\n" + ta.value; -}); +// Mock to request data +function requestData(obj) { + console.log("Loading data from server side"); + // Mock data on server side + setTimeout(function () { + // Mock to query data from DB. + var resRecords = DataGenerator.generateRecords(fields, { numRows: 10 }); // NOTE: It's random data + var sortField = obj.sortedField; + var sortOrder = obj.sortOrder; + resRecords = resRecords.sort(sortFx.bind(null, sortOrder, sortField)); + mockCallbackData({ + success: true, + data: resRecords + }); + }, 100); +} -document.getElementById("reset_btn").addEventListener("click", function() { - var sort = grid.api.getCoreGrid().getPlugin("SortableTitle"); - sort.clearSortState(); -}); +function sortFx(sortOrder, sortField, rowA, rowB) { + return compareFunction(rowA, rowB, sortField, sortOrder); +} + +function compareFunction(rowA, rowB, sortField, sortOrder) { + var valueA = rowA[sortField]; + var valueB = rowB[sortField]; + + if (sortOrder === "a") { + return valueA < valueB ? -1 : valueA > valueB ? 1 : 0; + } else { + return valueA > valueB ? -1 : valueA < valueB ? 1 : 0; + } +} + +var grid = document.getElementById("grid"); +grid.config = configObj;
- \ No newline at end of file +



diff --git a/template-145.html b/template-145.html index a779a73a..b83db8ac 100644 --- a/template-145.html +++ b/template-145.html @@ -1,51 +1,25 @@ -

Basic Sorting

-

Grid support sorting out of the box. By default, sorting is turned off for all columns. To turn it on, set sortableCoumns to true. This allow users to click at the Grid header section to sort the clicked column.

-
var config = {
-    // any other grid's options
-    sorting: {
-        sortableColumns: true,
-    }
-}
-
-

To turn the sorting on or off for a specific column, the sortable option is available in the column option.

-
var config = {
-    // any other grid's options
-    columns: [
-        { name: "Column 1", field: "field1", sortable: true },
-        { name: "Column 2", field: "field2" },
-    ],
-}
-
-

In some use cases, you may want to turn on sorting for a particular column based on another field. If so, you can set sortBy in the column option to any column field.

-
var config = {
-    // any other grid's options
-    sorting: {
-        sortableColumns: true,
-    },
-    columns: [
-        { name: "Column 1", field: "field1" },
-        { name: "Column 2", field: "field2", sortBy: "field1" },
-    ],
-}
-
-

Sorting programmatically

-

Use sortColumn from Grid api instance to sort the specified column without user interaction. If the second parameter is not defined, Grid will cycle through column sorting sequence defined in its settings.

-
var grid = document.getElementById("grid");
-grid.api.sortColumn(0, "a"); // Sort column index 0 in ascending order.
-grid.api.sortColumn(1); // Sort column index 1 and cycle through its sorting sequence.
+

Get Sorting States/Reset All

+

The getSortedColumns() method returns an array of the currently applied sorting states (with the colIndex and sortOrder properties).

+

Additionally, the clearSortState() method resets the current sorting states to their default neutral state.

+

A list of all sorting-related events can be found in the Events Handling section.

+
var sort = grid.api.getCoreGrid().getPlugin("SortableTitle");
+var states = sort.getSortedColumns(); // Return an array of the current active sorting states
+
+sort.clearSortState(); // Reset all sorting states to neutral
 
-

For all available sorting options and APIs, please visit SortableTitlePlugin

Example

-
html hr {
-    margin: 5px;
-}
-efx-grid {
+
efx-grid {
     height: 200px;
 }
+textarea {
+    width: 100%;
+    height: 50px;
+    margin: 10px 0;
+}
 
-
<button id="sort_btn1">Sort Column 1</button>
-<button id="sort_btn2">Sort Column 2</button>
-<hr>
+
<button id="get_btn">Get Current States</button>
+<button id="reset_btn">Clear All Sorting</button>
+<textarea id="output_ta" placeholder="Click at the grid header to sort"></textarea>
 <efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
@@ -57,18 +31,12 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -document.getElementById("sort_btn1").addEventListener("click", function(e){ - grid.api.sortColumn(0); -}); -document.getElementById("sort_btn2").addEventListener("click", function(e){ - grid.api.sortColumn(1); -}); - var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { sorting: { sortableColumns: true, + threeStatesSorting: true }, columns: [ {name: "Company", field: fields[0]}, @@ -82,5 +50,19 @@

Example

var grid = document.getElementById("grid"); grid.config = configObj; + +document.getElementById("get_btn").addEventListener("click", function() { + // Return an array of the current active sorting states + var sort = grid.api.getCoreGrid().getPlugin("SortableTitle"); + var states = sort.getSortedColumns(); + + var ta = document.getElementById('output_ta'); + ta.value = JSON.stringify(states, 2, null) + "\n" + ta.value; +}); + +document.getElementById("reset_btn").addEventListener("click", function() { + var sort = grid.api.getCoreGrid().getPlugin("SortableTitle"); + sort.clearSortState(); +});
\ No newline at end of file diff --git a/template-146.html b/template-146.html index 5a5971d4..a779a73a 100644 --- a/template-146.html +++ b/template-146.html @@ -1,30 +1,86 @@ -

Support

-

If you need help, simply go to the Stack Overflow, post your questions or difficulties, and provide your live example.

-

Creating a live example

-

Grid's dependencies are available for Code Sandbox(Devbox), making it simple to create your own live demonstration. The live example imitated issues are very significant because it helps us in our investigation and save us time. To create a live example page you can follow the below instructions:

-
    -
  • Sign up for a Code Sandbox (Devbox) account or log in if you already have one.
  • -
  • Open one of the following template. -
  • -
  • Fork the template by clicking the "Fork" button at the top right of the screen.
  • -
  • Modify the code in your live example as desired and save it by pressing Ctrl/Cmd + S.
  • -
  • Share the link by following below steps:
      -
    • Click "Share" button at the top right of the screen.
    • -
    • Select "Unlisted" option from the dropdown box on "Visbility" section.
    • -
    • Click "Move Devbox" button to change the draft to permanent one and get the link.
    • -
    • Uncheck "Include editor layout" to shorthen the link.
    • -
    • Click "Copy" button to copy the link. The link will be available in your system's clipboard.
    • -
    -
  • -
-

Existing live examples

-

All existing Grid live examples can be found here. You may fork or use some of the examples to illustrate your issue, if those examples have suitable setup for your use cases.

-
-
-
\ No newline at end of file +

Basic Sorting

+

Grid support sorting out of the box. By default, sorting is turned off for all columns. To turn it on, set sortableCoumns to true. This allow users to click at the Grid header section to sort the clicked column.

+
var config = {
+    // any other grid's options
+    sorting: {
+        sortableColumns: true,
+    }
+}
+
+

To turn the sorting on or off for a specific column, the sortable option is available in the column option.

+
var config = {
+    // any other grid's options
+    columns: [
+        { name: "Column 1", field: "field1", sortable: true },
+        { name: "Column 2", field: "field2" },
+    ],
+}
+
+

In some use cases, you may want to turn on sorting for a particular column based on another field. If so, you can set sortBy in the column option to any column field.

+
var config = {
+    // any other grid's options
+    sorting: {
+        sortableColumns: true,
+    },
+    columns: [
+        { name: "Column 1", field: "field1" },
+        { name: "Column 2", field: "field2", sortBy: "field1" },
+    ],
+}
+
+

Sorting programmatically

+

Use sortColumn from Grid api instance to sort the specified column without user interaction. If the second parameter is not defined, Grid will cycle through column sorting sequence defined in its settings.

+
var grid = document.getElementById("grid");
+grid.api.sortColumn(0, "a"); // Sort column index 0 in ascending order.
+grid.api.sortColumn(1); // Sort column index 1 and cycle through its sorting sequence.
+
+

For all available sorting options and APIs, please visit SortableTitlePlugin

+

Example

+
html hr {
+    margin: 5px;
+}
+efx-grid {
+    height: 200px;
+}
+
+
<button id="sort_btn1">Sort Column 1</button>
+<button id="sort_btn2">Sort Column 2</button>
+<hr>
+<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+document.getElementById("sort_btn1").addEventListener("click", function(e){
+    grid.api.sortColumn(0);
+});
+document.getElementById("sort_btn2").addEventListener("click", function(e){
+    grid.api.sortColumn(1);
+});
+
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { numRows: 10 });
+var configObj = {
+    sorting: {
+        sortableColumns: true,
+    },
+    columns: [
+        {name: "Company", field: fields[0]},
+        {name: "Market", field: fields[1], width: 120},
+        {name: "Last", field: fields[2], width: 100},
+        {name: "Net. Chng", field: fields[3], width: 100},
+        {name: "Industry", field: fields[4]}
+    ],
+    staticDataRows: records
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+
\ No newline at end of file diff --git a/template-147.html b/template-147.html index d0b22cff..5a5971d4 100644 --- a/template-147.html +++ b/template-147.html @@ -1,93 +1,30 @@ - - -

Data generator

-

DataGenerator class from grid utility packages is for generating data for testing purpose.

-

To generate data for feeding into Grid, use generateRecords(fields, options) method.

-

To add custom field data, use addFieldInfo(field, options or function) method.

-

Usage

-

DataGenerator class is located in the utility package as shown in the code snippet below:

-
import {DataGenerator} from "@refinitiv-ui/efx-grid/utils";
-
-var fields = ["id", "companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var genOptions = {
-    seed: 0,
-    numRows: 10
-};
-var records = DataGenerator.generateRecords(fields, genOptions);
-
-
html hr {
-    margin: 5px;
-}
-html input {
-    width: 50% !important;
-}
-textarea {
-    width: 100%;
-    height: 300px;
-}
-
-
<label for="field_in">Fields:</label>
-<input id="field_in" value="id, companyName, market, CF_LAST, CF_NETCHNG, industry">
-<hr>
-<label for="seed_in">Seed:</label>
-<input id="seed_in" type="number" value="0">
-<hr>
-<textarea id="msg_ta"></textarea>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-field_in.addEventListener("change", updateRecords);
-seed_in.addEventListener("change", updateRecords);
-
-function updateRecords() {
-    var fields = field_in.value.split(/\W+/);
-    var seedNum = +(seed_in.value);
-    if(Number.isNaN(seedNum)) {
-        seedNum = null;
-    }
-    var records = DataGenerator.generateRecords(fields, {
-        seed: seedNum,
-        numRows: 6
-    });
-    msg_ta.value = JSON.stringify(records, null, 2);
-}
-
-updateRecords();
-
-

DataGenerator API Reference

-

DataGenerator(seedopt)

Type Definitions

-
typedef

DataOptions

Options for generating data
Type:
Object
Properties:
Name Type Attributes Description
seed number <optional>
Seed for randomization. If seed is not specified (default), new set of data will be generated every time. Otherwise, the same set of data will be generated.
numRows number <optional>
Number of rows to be generated
rowCount number <optional>
Alias to numRows
-
typedef

FieldInformation

Information object for defining how data are generated for a specific field
Type:
Object
Properties:
Name Type Attributes Description
type string <optional>
Available types are number, float, boolean, set, function, and isoDate
prefix string <optional>
Add a text prefix to the data
suffix string <optional>
Add a text suffix to the data
min number <optional>
Minimum value of the numeric data
max number <optional>
Maximum value of the numeric data. This is exclusive (not included in the result).
prec string <optional>
Precision (place number after the decimal point) of the numeric data.
fixedValue string <optional>
Single/static/constant value
members Array <optional>
List of possible data when the type is "set"
generate function <optional>
Function for generating data when the type is "function"

Methods

-
function

addFieldInfo(field, options)

Parameters:
field
string
options
-
function

generate(fields, optionsopt) → {Array.<Array>}

Generate 2 dimensional array of data from the specified field and options. Note that 2D array data structure is not recommended for usage due to the position of fields/columns can be changed at runtime.
Parameters:
fields
string | Array.<string>
options
<optional>
Returns:
Array.<Array>
2D Array of data
-
function

generateRecord(fields, optionsopt) → {Object}

Parameters:
fields
string | Array.<string>
options
<optional>
Returns:
Object
Object with the given fields as its keys
-
function

generateRecords(fields, optionsopt) → {Array.<Object>}

Parameters:
fields
string | Array.<string>
options
<optional>
Configuration object or number of rows
Returns:
Array.<Object>
Array of object with the given fields as its keys
-
function

randBetween(minopt, maxopt, seedopt) → {number}

Return a integer random number in the range min - max (inclusive of min, but not max).
Parameters:
min
number
<optional>
max
number
<optional>
Exclusive value
seed
number
<optional>
Returns:
number
-
function

randBoolean(seedopt) → {boolean}

Parameters:
seed
number
<optional>
Returns:
boolean
-
function

randDate(minopt, maxopt, seedopt) → {Date}

Parameters:
min
number | Object
<optional>
minimum timestamp or date object
max
number | Object
<optional>
minimum timestamp or date object
seed
number
<optional>
Returns:
Date
-
function

randIndex(max, seedopt) → {number}

Return a integer random number in the range 0 - max
(exclusive of max). It is usefull in some cases for example,
if you want to get a random member of an array,
just get a random index via randIndex(ary.length).
Parameters:
max
number
Exclusive value
seed
number
<optional>
Returns:
number
-
function

randInt(min, max, seedopt) → {number}

Return an interger random number in the range min - max (inclusive of min and max).
Parameters:
min
number
max
number
Inclusive value
seed
number
<optional>
Returns:
number
-
function

randMember(set, seedopt) → {*}

Return a random member of set or single character in the range of A to Z
Parameters:
set
Array
seed
number
<optional>
Returns:
*
-
function

randNumber(minopt, maxopt, precopt, seedopt) → {number}

Return a floating-point random number in the range min - max (inclusive of min, but not max) with prec digits of precision.
Parameters:
min
number
<optional>
[default: 0]
max
number
<optional>
[default: 100]
Exclusive value
prec
number | null
<optional>
seed
number
<optional>
Returns:
number
-
function

randString(minopt, maxopt, subTypeopt, seedopt) → {string}

Parameters:
min
number
<optional>
max
number
<optional>
subType
string
<optional>
"w"/"W" = word, "s"/"S" = sentence
seed
number
<optional>
Returns:
string
-
function

toRecords(data2D, fieldsopt) → {Array.<Object>}

Convert 2D Array to Array of records
Parameters:
data2D
Array.<Array>
Array of values
fields
Array.<string>
<optional>
Keys to be mapped on the output records.
Returns:
Array.<Object>
records
-
function

generate(fields, optionsopt) → {Array.<Array>}

Generate 2 dimensional array of data from the specified field and options. Note that 2D array data structure is not recommended for usage due to the position of fields/columns can be changed at runtime.
Parameters:
fields
string | Array.<string>
options
<optional>
Returns:
Array.<Array>
2D Array of data
-
function

generateQuoteData(field, optionsopt) → {Object}

Parameters:
field
string
options
<optional>
Returns:
Object
Object with value, formattedValue and other properties
-
function

generateRecords(fields, optionsopt) → {Array.<Object>}

Parameters:
fields
string | Array.<string>
options
number | Object
<optional>
Returns:
Array.<Object>
Array of data object
-
function

getSeed() → {number}

Returns:
number
-
function

randBetween(minopt, maxopt) → {number}

Parameters:
min
number
<optional>
max
number
<optional>
Exclusive value
Returns:
number
-
function

randBoolean() → {boolean}

Returns:
boolean
-
function

randDate(minopt, maxopt) → {Date}

Parameters:
min
number | Object
<optional>
minimum timestamp or date object
max
number | Object
<optional>
minimum timestamp or date object
Returns:
Date
-
function

randIndex(max) → {number}

Parameters:
max
number
Exclusive value
Returns:
number
-
function

randInt(min, max) → {number}

Parameters:
min
number
max
number
Inclusive value
Returns:
number
-
function

randMember(set) → {*}

Parameters:
set
Array
Returns:
*
-
function

randNumber(minopt, maxopt, precopt) → {number}

Parameters:
min
number
<optional>
[default: 0]
max
number
<optional>
[default: 100]
Exclusive value
prec
number | null
<optional>
Returns:
number
-
function

randString(minopt, maxopt) → {string}

Parameters:
min
number
<optional>
max
number
<optional>
Exclusive value
Returns:
string
-
function

setSeed(seed)

Parameters:
seed
number
\ No newline at end of file +

Support

+

If you need help, simply go to the Stack Overflow, post your questions or difficulties, and provide your live example.

+

Creating a live example

+

Grid's dependencies are available for Code Sandbox(Devbox), making it simple to create your own live demonstration. The live example imitated issues are very significant because it helps us in our investigation and save us time. To create a live example page you can follow the below instructions:

+
    +
  • Sign up for a Code Sandbox (Devbox) account or log in if you already have one.
  • +
  • Open one of the following template. +
  • +
  • Fork the template by clicking the "Fork" button at the top right of the screen.
  • +
  • Modify the code in your live example as desired and save it by pressing Ctrl/Cmd + S.
  • +
  • Share the link by following below steps:
      +
    • Click "Share" button at the top right of the screen.
    • +
    • Select "Unlisted" option from the dropdown box on "Visbility" section.
    • +
    • Click "Move Devbox" button to change the draft to permanent one and get the link.
    • +
    • Uncheck "Include editor layout" to shorthen the link.
    • +
    • Click "Copy" button to copy the link. The link will be available in your system's clipboard.
    • +
    +
  • +
+

Existing live examples

+

All existing Grid live examples can be found here. You may fork or use some of the examples to illustrate your issue, if those examples have suitable setup for your use cases.

+
+
+
\ No newline at end of file diff --git a/template-148.html b/template-148.html index 4592f588..d0b22cff 100644 --- a/template-148.html +++ b/template-148.html @@ -1,168 +1,38 @@ -

Multi-table feature

-

Multiple grids can be created within a single page. They are independent from each other. A change made to one grid won't affect on the other grids. Sometimes, you want multiple instances of the same grid to make more room for displaying data. MultiTableManager is created to support such case. MultiTableManager will create multiple instances of the same grid and syncronize any column related change across all those instances. Each grid created by MultiTableManager will always have the same column configuration and the extensions. You can have different different row content on each grid.

-
-

Note that MultiTableManager is just a helper class object. It is not a Grid extension which is tied to single grid instance. It can be viewed as another wrapper that manages multiple Grid instances.

-
-

Support features

-

MultiTableManager is still in development and support only some basic features as listed below:

-
    -
  • Each table will have the same width and become inline-block element.
  • -
  • Each table will have the same number of rows and columns.
  • -
  • Column selection will be displayed on each table.
  • -
  • Column resizing will be applied on each table.
  • -
  • Column fitting will be applied on each table.
  • -
  • Column insertion, removal, and reordering will be applied on each table.
  • -
  • Row selection can be moved across multiple grids through keyboard navigation. Row selection can be only active for one grid at any time.
  • -
+

Data generator

+

DataGenerator class from grid utility packages is for generating data for testing purpose.

+

To generate data for feeding into Grid, use generateRecords(fields, options) method.

+

To add custom field data, use addFieldInfo(field, options or function) method.

Usage

-

To use multi-table feature, you need to import MultiTableManager, a helper, from package. Then, initialize the helper by supplying Grid element. The element will be used as a primary table for creating another table. Lastly, initialize the Grid element by using setGridConfig method from the helper to specify configuration.

-

To adjust number of tables, use setTableCount method.

-

To get Grid element, use getTable method.

-

The basic setup process is shown in the example below:

-
import MultiTableManager from "@refinitiv-ui/efx-grid/utils";
+

DataGenerator class is located in the utility package as shown in the code snippet below:

+
import {DataGenerator} from "@refinitiv-ui/efx-grid/utils";
 
-var gridElement = document.getElementById("grid");
-var mgr = new MultiTableManager(gridElement);
-
-var configObj = {
-    /* grid configuration */
+var fields = ["id", "companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var genOptions = {
+    seed: 0,
+    numRows: 10
 };
-mgr.setGridConfig(configObj);
-
-mgr.setTableCount(3); // Or any other number
+var records = DataGenerator.generateRecords(fields, genOptions);
 
-

Multi-table example

-
html hr {
+
html hr {
     margin: 5px;
 }
-efx-grid {
-    margin: 0 5px 5px;
-    vertical-align: top;
+html input {
+    width: 50% !important;
 }
-#h_scrollbar_host {
-    height: 400px;
-}
-
-
<button id="table_btn1">Table Count 1</button>
-<button id="table_btn2">Table Count 2</button>
-<button id="table_btn3">Table Count 3</button>
-<button id="table_btn4">Table Count 4</button>
-<hr>
-<div id="v_scrollbar_host">
-    <div id="h_scrollbar_host">
-        <efx-grid id="grid"></efx-grid>
-    </div>
-</div>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var records = DataGenerator.generateRecords(fields, { numRows: 5 });
-
-var configObj = {
-    columns: [
-        {name: "Company", field: fields[0], width: 100},
-        {name: "Market", field: fields[1], width: 100},
-        {name: "Last", field: fields[2], width: 100}
-    ],
-    staticDataRows: records,
-    extensions: [
-        new RowSelection(),
-        new ColumnSelection(),
-        new ColumnResizing(),
-        new ColumnFitter(),
-        new ColumnDragging()
-    ]
-};
-
-var grid = document.getElementById("grid");
-var mgr = new MultiTableManager(grid);
-// You can place grids side by side by using the following commands
-// var vScrollbarHost = document.getElementById("v_scrollbar_host");
-// var hScrollbarHost = document.getElementById("h_scrollbar_host");
-// MultiTableManager.synchronizeVScrollbar(vScrollbarHost, hScrollbarHost, grid);
-
-mgr.setGridConfig(configObj);
-mgr.setTableCount(3);
-
-document.getElementById("table_btn1").addEventListener("click", function(e) {
-    mgr.setTableCount(1);
-});
-document.getElementById("table_btn2").addEventListener("click", function(e) {
-    mgr.setTableCount(2);
-});
-document.getElementById("table_btn3").addEventListener("click", function(e) {
-    mgr.setTableCount(3);
-});
-document.getElementById("table_btn4").addEventListener("click", function(e) {
-    mgr.setTableCount(4);
-});
-setInterval(function simulateDataUpdate() {
-    if(!grid.api) {
-        return;
-    }
-    var rowCount = mgr.getRowCount();
-    for(var i = 0; i < 4; ++i) {
-        var tbl = mgr.getTable(i);
-        if(!tbl) {
-            break;
-        }
-        for(var r = 0; r < rowCount; ++r) {
-            if(!DataGenerator.randInt(0, 4)) {
-                var record = DataGenerator.generateRecord(fields);
-                tbl.api.setRowData(r, record);
-            }
-        }
-    }
-}, 500);
-
-

Multi-table: wrap mode example

-

In wrap mode, a single table will be used as a primary table and wrapped by specified number of rows. After wrapping, multiple secondary tables will be created with specified number of rows to represent the rows from the primary table. The main difference between wrap mode and multi-table mode is that content rows, in wrap mode, of each table are based on a single primary table. Any change on a row from the primary table will also apply to corresponding row on one of the secondary tables, and vice versa. In multi-table mode, rows in one table are independent from rows in other tables.

-

To enable wrap mode, use wrapTable method with number of wrapping rows as its parameter.

-

To disable wrap mode, use wrapTable method with 0 as its parameter.

-

If you are in multi-table mode, wrapTable method will automatically remove any existing table and switch to wrap mode.

-

If you are in wrap mode, setTableCount method will automatically disable wrap-mode and switch to multi-table mode.

-
-

Note that original table is still kept intact after the wrapping, even though it is hidden from view. getTable(0) will return the original table.

-
-
html hr {
-    margin: 5px;
-}
-efx-grid {
-    margin: 0 5px 5px;
-    vertical-align: top;
-}
-#h_scrollbar_host {
-    height: 250px;
+textarea {
+    width: 100%;
+    height: 300px;
 }
 
-
<button id="wrap_btn1">Wrap 3 rows</button>
-<button id="wrap_btn2">Wrap 4 rows</button>
-<button id="wrap_btn3">Wrap 5 rows</button>
-<button id="wrap_btn4">Disable wrap mode</button>
-<hr>
-<button id="set_btn1">Set Data on the second table</button>
-<button id="set_btn2">Set Data on the third table</button>
-<button id="add_row_btn">Add row</button>
-<button id="remove_row_btn">Remove row</button>
+
<label for="field_in">Fields:</label>
+<input id="field_in" value="id, companyName, market, CF_LAST, CF_NETCHNG, industry">
 <hr>
-<button id="add_col_btn">Add Column</button>
-<button id="remove_col_btn">Remove Column</button>
+<label for="seed_in">Seed:</label>
+<input id="seed_in" type="number" value="0">
 <hr>
-<div id="v_scrollbar_host">
-    <div id="h_scrollbar_host">
-        <efx-grid id="grid"></efx-grid>
-    </div>
-</div>
+<textarea id="msg_ta"></textarea>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -173,197 +43,51 @@ 

Multi-table example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); - -var configObj = { - sorting: { - sortableColumns: true - }, - defaultColumnOptions: { - minWidth: 24 - }, - columns: [ - {name: fields[0], width: 100, field: fields[0]}, - {name: fields[2], width: 100, field: fields[2], formatType: "number", colorText: true }, - {name: fields[3], width: 100, field: fields[3], formatType: "percent", blinking: true } - ], - staticDataRows: records, - extensions: [ - new RowSelection(), - new ColumnSelection(), - new ColumnResizing(), - new ColumnFitter(), - new ColumnDragging() - ] -}; - -var grid = document.getElementById("grid"); -var mgr = new MultiTableManager(grid); -mgr.setGridConfig(configObj); - -wrap_btn1.addEventListener("click", function() { - mgr.wrapTable(3); -}); -wrap_btn2.addEventListener("click", function() { - mgr.wrapTable(4); -}); -wrap_btn3.addEventListener("click", function() { - mgr.wrapTable(5); -}); -wrap_btn4.addEventListener("click", function() { - mgr.wrapTable(0); -}); -add_row_btn.addEventListener("click", function() { - mgr.insertRow({}); -}); -remove_row_btn.addEventListener("click", function() { - mgr.removeRow(); -}); -add_col_btn.addEventListener("click", function() { - mgr.insertColumn({field: "industry", width: 80}); -}); -remove_col_btn.addEventListener("click", function() { - mgr.removeColumn(mgr.getColumnCount() - 1); -}); -set_btn1.addEventListener("click", function() { - randomlySetData(mgr.getTable(1)); -}); -set_btn2.addEventListener("click", function() { - randomlySetData(mgr.getTable(2)); -}); - -setInterval(function simulateDataUpdate() { - var tblCount = mgr.getTableCount(); - - for(var i = 0; i < tblCount; ++i) { - if(Math.random() > 0.6) { - randomlySetData(mgr.getTable(i)); - } - } -}, 500); - -function randomlySetData(tbl) { - if(!tbl || !tbl.api) { - return; +field_in.addEventListener("change", updateRecords); +seed_in.addEventListener("change", updateRecords); + +function updateRecords() { + var fields = field_in.value.split(/\W+/); + var seedNum = +(seed_in.value); + if(Number.isNaN(seedNum)) { + seedNum = null; } - var rowCount = mgr.getRowCount(); - for(var i = 0; i < rowCount; ++i) { - if(Math.random() > 0.7) { - var rowDef = tbl.api.getRowDefinition(i); - if(rowDef) { - rowDef.setRowData(DataGenerator.generateRecord(fields)); - } - } - } -} -
-

Positioning grids side by side with vertical scrollbar syncronization

-

You can display multiple grids side by side using CSS as shown in the above example. However, it does not work when you want to have a single vertical scrollbar for multiple grids. If normal native scrollbar is used, all rows in a grid have to be displayed and cannot be virtualized. Large number of rows in each grid can introduce performance problem. You can use Grid's scrollbars instead of native scrollbars to enable row virtualization and improve the performance.

-

To link multiple grids together and have only one single vertical scrollbar, use MultiTableManager.synchronizeVScrollbar method. The method requires two elements to host the scrollbars and array of Grid elements. The first element is for hosting Grid vertical scrollbar. The second element is for hosting native horizontal scrollbar and Grid elements. The vertical scrollbar requires separated host element because it has to be float over view and not moved when horizontal scrolling occurs. The setup for element structure is shown below:

-
<div id="v_scrollbar_host">
-    <div id="h_scrollbar_host">
-        <efx-grid></efx-grid>
-        <efx-grid></efx-grid>
-    </div>
-</div>
-
-

The height for the grid can be specified on the vertical scrollbar host. If so, make sure that the height of horizontal scrollbar host is set to 100%. The width of the grid can be set on the element itself or on every column of the grid.

-

Side by side Grids Example

-
efx-grid+efx-grid {
-    margin-left: 5px;
+    var records = DataGenerator.generateRecords(fields, {
+        seed: seedNum,
+        numRows: 6
+    });
+    msg_ta.value = JSON.stringify(records, null, 2);
 }
-#v_scrollbar_host {
-    height: 300px;
-}
-#h_scrollbar_host {
-    height: 100%;
-}
-#grid_2 {
-    width: 500px;
-}
-
-
<div id="v_scrollbar_host">
-    <div id="h_scrollbar_host">
-        <efx-grid id="grid_1"></efx-grid>
-        <efx-grid id="grid_2"></efx-grid>
-    </div>
-</div>
-<hr>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var gen = DataGenerator;
-var fields = ["companyName","percent", "number_2", "bid", "ask"];
-
-var records1 = gen.generateRecords(fields, {seed: 1, rowCount: 20});
-var records2 = gen.generateRecords(fields, {seed: 100, rowCount: 20});
-
-var configObj1 = {
-    defaultColumnOptions: {
-        width: 100
-    },
-    sorting: {
-        initialSort: {
-            colIndex: 3,
-            sortOrder: "d"
-        }
-    },
-    columns: [
-        {name: fields[0], field: fields[0], width: 120},
-        {name: fields[1], field: fields[1]},
-        {name: fields[2], field: fields[2], colorText: true},
-        {name: "Bid", field: "bid"}
-    ],
-    staticDataRows: records1
-};
-var configObj2 = {
-    sorting: {
-        initialSort: {
-            colIndex: 0,
-            sortOrder: "a"
-        }
-    },
-    columns: [
-        {name: "Ask", field: "ask"},
-        {name: fields[2], field: fields[2], colorText: true},
-        {name: fields[1], field: fields[1]},
-        {name: fields[0], field: fields[0]}
-    ],
-    staticDataRows: records2
-};
-
-var grid1 = document.getElementById("grid_1");
-var grid2 = document.getElementById("grid_2");
-
-grid1.config = configObj1;
-grid2.config = configObj2;
 
-MultiTableManager.synchronizeVScrollbar(
-    document.getElementById("v_scrollbar_host"),
-    document.getElementById("h_scrollbar_host"),
-    [grid1, grid2]
-);
+updateRecords();
 
-

MultiTableManager API Reference

-

MultiTableManager(gridElem)

Methods

-
function

synchronizeVScrollbar(vScrollbarHost, hScrollbarHost, gridElems) → {Promise.<Array>}

Parameters:
vScrollbarHost
Element
Host element for the vertical scrollbar.
hScrollbarHost
Element
Host element for the horizontal scrollbar. This element must be a child of the vScrollbarHost element.
gridElems
Array.<Element>
Array of grid elements. The first element will be treated as primary grid.
Returns:
Promise.<Array>
-
function

dispose()

-
function

getColumnCount() → {number}

Returns:
number
-
function

getRowCount() → {number}

Returns:
number
-
function

getTable(atopt) → {Element}

Parameters:
at
number
<optional>
Returns:
Element
-
function

getTableCount() → {number}

Returns:
number
-
function

insertColumn(columnOption, idxopt)

Parameters:
columnOption
*
String will be treated as field, while object is treated as the column options
idx
number
<optional>
-
function

insertRow(rowOptionopt, atopt)

Parameters:
rowOption
Object
<optional>
at
number
<optional>
-
function

removeColumn(colRef)

Parameters:
colRef
*
Column reference
-
function

removeRow(atopt)

Parameters:
at
number
<optional>
-
function

setGridConfig(configObjopt)

Parameters:
configObj
Object
<optional>
-
function

setTableCount(num)

Parameters:
num
number
Number of tables. Number cannot be less than one.
-
function

wrapTable(rowCount)

Parameters:
rowCount
number
Number of row per table. Set number to zero to turn off wrap mode.
\ No newline at end of file +

DataGenerator API Reference

+

DataGenerator(seedopt)

Type Definitions

+
typedef

DataOptions

Options for generating data
Type:
Object
Properties:
Name Type Attributes Description
seed number <optional>
Seed for randomization. If seed is not specified (default), new set of data will be generated every time. Otherwise, the same set of data will be generated.
numRows number <optional>
Number of rows to be generated
rowCount number <optional>
Alias to numRows
+
typedef

FieldInformation

Information object for defining how data are generated for a specific field
Type:
Object
Properties:
Name Type Attributes Description
type string <optional>
Available types are number, float, boolean, set, function, and isoDate
prefix string <optional>
Add a text prefix to the data
suffix string <optional>
Add a text suffix to the data
min number <optional>
Minimum value of the numeric data
max number <optional>
Maximum value of the numeric data. This is exclusive (not included in the result).
prec string <optional>
Precision (place number after the decimal point) of the numeric data.
fixedValue string <optional>
Single/static/constant value
members Array <optional>
List of possible data when the type is "set"
generate function <optional>
Function for generating data when the type is "function"

Methods

+
function

addFieldInfo(field, options)

Parameters:
field
string
options
+
function

generate(fields, optionsopt) → {Array.<Array>}

Generate 2 dimensional array of data from the specified field and options. Note that 2D array data structure is not recommended for usage due to the position of fields/columns can be changed at runtime.
Parameters:
fields
string | Array.<string>
options
<optional>
Returns:
Array.<Array>
2D Array of data
+
function

generateRecord(fields, optionsopt) → {Object}

Parameters:
fields
string | Array.<string>
options
<optional>
Returns:
Object
Object with the given fields as its keys
+
function

generateRecords(fields, optionsopt) → {Array.<Object>}

Parameters:
fields
string | Array.<string>
options
<optional>
Configuration object or number of rows
Returns:
Array.<Object>
Array of object with the given fields as its keys
+
function

randBetween(minopt, maxopt, seedopt) → {number}

Return a integer random number in the range min - max (inclusive of min, but not max).
Parameters:
min
number
<optional>
max
number
<optional>
Exclusive value
seed
number
<optional>
Returns:
number
+
function

randBoolean(seedopt) → {boolean}

Parameters:
seed
number
<optional>
Returns:
boolean
+
function

randDate(minopt, maxopt, seedopt) → {Date}

Parameters:
min
number | Object
<optional>
minimum timestamp or date object
max
number | Object
<optional>
minimum timestamp or date object
seed
number
<optional>
Returns:
Date
+
function

randIndex(max, seedopt) → {number}

Return a integer random number in the range 0 - max
(exclusive of max). It is usefull in some cases for example,
if you want to get a random member of an array,
just get a random index via randIndex(ary.length).
Parameters:
max
number
Exclusive value
seed
number
<optional>
Returns:
number
+
function

randInt(min, max, seedopt) → {number}

Return an interger random number in the range min - max (inclusive of min and max).
Parameters:
min
number
max
number
Inclusive value
seed
number
<optional>
Returns:
number
+
function

randMember(set, seedopt) → {*}

Return a random member of set or single character in the range of A to Z
Parameters:
set
Array
seed
number
<optional>
Returns:
*
+
function

randNumber(minopt, maxopt, precopt, seedopt) → {number}

Return a floating-point random number in the range min - max (inclusive of min, but not max) with prec digits of precision.
Parameters:
min
number
<optional>
[default: 0]
max
number
<optional>
[default: 100]
Exclusive value
prec
number | null
<optional>
seed
number
<optional>
Returns:
number
+
function

randString(minopt, maxopt, subTypeopt, seedopt) → {string}

Parameters:
min
number
<optional>
max
number
<optional>
subType
string
<optional>
"w"/"W" = word, "s"/"S" = sentence
seed
number
<optional>
Returns:
string
+
function

toRecords(data2D, fieldsopt) → {Array.<Object>}

Convert 2D Array to Array of records
Parameters:
data2D
Array.<Array>
Array of values
fields
Array.<string>
<optional>
Keys to be mapped on the output records.
Returns:
Array.<Object>
records
+
function

generate(fields, optionsopt) → {Array.<Array>}

Generate 2 dimensional array of data from the specified field and options. Note that 2D array data structure is not recommended for usage due to the position of fields/columns can be changed at runtime.
Parameters:
fields
string | Array.<string>
options
<optional>
Returns:
Array.<Array>
2D Array of data
+
function

generateQuoteData(field, optionsopt) → {Object}

Parameters:
field
string
options
<optional>
Returns:
Object
Object with value, formattedValue and other properties
+
function

generateRecords(fields, optionsopt) → {Array.<Object>}

Parameters:
fields
string | Array.<string>
options
number | Object
<optional>
Returns:
Array.<Object>
Array of data object
+
function

getSeed() → {number}

Returns:
number
+
function

randBetween(minopt, maxopt) → {number}

Parameters:
min
number
<optional>
max
number
<optional>
Exclusive value
Returns:
number
+
function

randBoolean() → {boolean}

Returns:
boolean
+
function

randDate(minopt, maxopt) → {Date}

Parameters:
min
number | Object
<optional>
minimum timestamp or date object
max
number | Object
<optional>
minimum timestamp or date object
Returns:
Date
+
function

randIndex(max) → {number}

Parameters:
max
number
Exclusive value
Returns:
number
+
function

randInt(min, max) → {number}

Parameters:
min
number
max
number
Inclusive value
Returns:
number
+
function

randMember(set) → {*}

Parameters:
set
Array
Returns:
*
+
function

randNumber(minopt, maxopt, precopt) → {number}

Parameters:
min
number
<optional>
[default: 0]
max
number
<optional>
[default: 100]
Exclusive value
prec
number | null
<optional>
Returns:
number
+
function

randString(minopt, maxopt) → {string}

Parameters:
min
number
<optional>
max
number
<optional>
Exclusive value
Returns:
string
+
function

setSeed(seed)

Parameters:
seed
number
\ No newline at end of file diff --git a/template-149.html b/template-149.html index e30678b5..4592f588 100644 --- a/template-149.html +++ b/template-149.html @@ -1,58 +1,60 @@ -

Native HTML table

-

Sometimes you only need a simple table for your app. Native HTML table could be used in place of Grid component for quick and easy table layout. The main advantages of native HTML table is simplicity, flexibility, and style customization. However, manipulating HTML element directly could be tedious and cumbersome. Table class from our utility package can help managing native HTML table with ease.

+

Multi-table feature

+

Multiple grids can be created within a single page. They are independent from each other. A change made to one grid won't affect on the other grids. Sometimes, you want multiple instances of the same grid to make more room for displaying data. MultiTableManager is created to support such case. MultiTableManager will create multiple instances of the same grid and syncronize any column related change across all those instances. Each grid created by MultiTableManager will always have the same column configuration and the extensions. You can have different different row content on each grid.

-

Note that Table class only provides JavaScript logic for HTML element manipulation. Styles and CSS are not provided by Grid utility package.

+

Note that MultiTableManager is just a helper class object. It is not a Grid extension which is tied to single grid instance. It can be viewed as another wrapper that manages multiple Grid instances.

+

Support features

+

MultiTableManager is still in development and support only some basic features as listed below:

+
    +
  • Each table will have the same width and become inline-block element.
  • +
  • Each table will have the same number of rows and columns.
  • +
  • Column selection will be displayed on each table.
  • +
  • Column resizing will be applied on each table.
  • +
  • Column fitting will be applied on each table.
  • +
  • Column insertion, removal, and reordering will be applied on each table.
  • +
  • Row selection can be moved across multiple grids through keyboard navigation. Row selection can be only active for one grid at any time.
  • +

Usage

-

Table class is located in the utility package as shown in the code snippet below:

-
import {Table} from "@refinitiv-ui/efx-grid/utils";
+

To use multi-table feature, you need to import MultiTableManager, a helper, from package. Then, initialize the helper by supplying Grid element. The element will be used as a primary table for creating another table. Lastly, initialize the Grid element by using setGridConfig method from the helper to specify configuration.

+

To adjust number of tables, use setTableCount method.

+

To get Grid element, use getTable method.

+

The basic setup process is shown in the example below:

+
import MultiTableManager from "@refinitiv-ui/efx-grid/utils";
 
-var tableInstance = new Table(divElement, {
-    colCount: 4,
-    rowCount: 5
-});
-
-
table td {
-    text-align: center;
-}
-
-
<div id="table_div">
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+var gridElement = document.getElementById("grid");
+var mgr = new MultiTableManager(gridElement);
 
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var tableInstance = new Table(table_div, {
-    colCount: 4,
-    rowCount: 5
-});
+var configObj = {
+    /* grid configuration */
+};
+mgr.setGridConfig(configObj);
 
-var rowCount = tableInstance.getRowCount();
-for(var r = 0; r < rowCount; ++r) {
-    tableInstance.getCellsInRow(r).forEach(function(cell, colIndex) {
-        cell.textContent = ([colIndex, r]).join(", ");
-    });
-}
+mgr.setTableCount(3); // Or any other number
 
-

Table initialization

-

Table class takes two parameters for its constructor. The first parameter is a placeholder element. It is used for positioning the table in the HTML document. The second parameter is a table configuration object, where you can define various parameters and options (e.g., number of columns, number of rows, width, height). For all available options, see Table API Reference section.

-
html hr {
-    margin-top: 5px;
-    margin-bottom: 10px;
+

Multi-table example

+
html hr {
+    margin: 5px;
+}
+efx-grid {
+    margin: 0 5px 5px;
+    vertical-align: top;
+}
+#h_scrollbar_host {
+    height: 400px;
 }
 
-
<big>Table with default column size</big>
-<div id="table_div1"></div>
+
<button id="table_btn1">Table Count 1</button>
+<button id="table_btn2">Table Count 2</button>
+<button id="table_btn3">Table Count 3</button>
+<button id="table_btn4">Table Count 4</button>
 <hr>
-<big>Table with fixed column size and header section</big>
-<div id="table_div2"></div>
+<div id="v_scrollbar_host">
+    <div id="h_scrollbar_host">
+        <efx-grid id="grid"></efx-grid>
+    </div>
+</div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -63,136 +65,104 @@ 

Usage

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var tableDiv1 = document.getElementById("table_div1"); -var tbl1 = new Table(tableDiv1, { - colCount: 4, - rowCount: 5, - cellHeight: 30 +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { numRows: 5 }); + +var configObj = { + columns: [ + {name: "Company", field: fields[0], width: 100}, + {name: "Market", field: fields[1], width: 100}, + {name: "Last", field: fields[2], width: 100} + ], + staticDataRows: records, + extensions: [ + new RowSelection(), + new ColumnSelection(), + new ColumnResizing(), + new ColumnFitter(), + new ColumnDragging() + ] +}; + +var grid = document.getElementById("grid"); +var mgr = new MultiTableManager(grid); +// You can place grids side by side by using the following commands +// var vScrollbarHost = document.getElementById("v_scrollbar_host"); +// var hScrollbarHost = document.getElementById("h_scrollbar_host"); +// MultiTableManager.synchronizeVScrollbar(vScrollbarHost, hScrollbarHost, grid); + +mgr.setGridConfig(configObj); +mgr.setTableCount(3); + +document.getElementById("table_btn1").addEventListener("click", function(e) { + mgr.setTableCount(1); }); -var tableDiv2 = document.getElementById("table_div2"); -var tbl2 = new Table(tableDiv2, { - colCount: 4, - rowCount: 5, - cellWidth: 100, - cellHeight: 30, - header: 1 +document.getElementById("table_btn2").addEventListener("click", function(e) { + mgr.setTableCount(2); }); -tbl2.getHeader().getCellsInRow(0).forEach(function(cell, idx) { - cell.textContent = "Header " + (idx + 1); +document.getElementById("table_btn3").addEventListener("click", function(e) { + mgr.setTableCount(3); }); +document.getElementById("table_btn4").addEventListener("click", function(e) { + mgr.setTableCount(4); +}); +setInterval(function simulateDataUpdate() { + if(!grid.api) { + return; + } + var rowCount = mgr.getRowCount(); + for(var i = 0; i < 4; ++i) { + var tbl = mgr.getTable(i); + if(!tbl) { + break; + } + for(var r = 0; r < rowCount; ++r) { + if(!DataGenerator.randInt(0, 4)) { + var record = DataGenerator.generateRecord(fields); + tbl.api.setRowData(r, record); + } + } + } +}, 500);
-

Table structure

-

Table class generates HTML elements and table structure based on the given configuration. The general structure created by the class will look like the code snippet below:

-
<div>
-    <table>
-        <colgroup>
-            <col>
-            ...
-        </colgroup>
-        <thead>
-            <tr>
-                <th></th>
-                ...
-            <tr>
-            ...
-        </thead>
-        <tbody>
-            <tr>
-                <td></td>
-                ...
-            </tr>
-            ...
-        </tbody>
-    </table>
-</div>
-
-

Table class instance itself represent the placeholder element (root element) and not the table element. The table below shows how to get corresponding element from the Table instance.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ElementAPI
Placeholder elementTable.getElement()
tableTable.getTableElement()
tbodyTable.getBody().getElement()
theadTable.getHeader().getElement()
tfootTable.getFooter().getElement()
trTable.getRow(r), Table.getBody().getRow(r)
td (tbody)Table.getCell(c, r), Table.getBody().getCell(c, r)
th (thead)Table.getHeaderCell(c, r), Table.getHeader().getCell(c, r)
td (tfoot)Table.getFooterCell(c, r), Table.getFooter().getCell(c, r)
-

Table manipulation

-

With Table class, you can add and remove rows and columns at runtime. For changing content and styles, you need to retrieve the element from Table instance, and then manipulate the element properties directly.

-

To change number of rows, use addRows and removeRows methods.

-

To change number of columns, use addColumns and removeColumns methods.

-

The example below also shows how to change row height of each row in the table.

-
html hr {
+

Multi-table: wrap mode example

+

In wrap mode, a single table will be used as a primary table and wrapped by specified number of rows. After wrapping, multiple secondary tables will be created with specified number of rows to represent the rows from the primary table. The main difference between wrap mode and multi-table mode is that content rows, in wrap mode, of each table are based on a single primary table. Any change on a row from the primary table will also apply to corresponding row on one of the secondary tables, and vice versa. In multi-table mode, rows in one table are independent from rows in other tables.

+

To enable wrap mode, use wrapTable method with number of wrapping rows as its parameter.

+

To disable wrap mode, use wrapTable method with 0 as its parameter.

+

If you are in multi-table mode, wrapTable method will automatically remove any existing table and switch to wrap mode.

+

If you are in wrap mode, setTableCount method will automatically disable wrap-mode and switch to multi-table mode.

+
+

Note that original table is still kept intact after the wrapping, even though it is hidden from view. getTable(0) will return the original table.

+
+
html hr {
     margin: 5px;
 }
-i:empty {
-    padding-left: 20px;
-}
-.compact td, .compact th {
-    padding-top: 2px;
-    padding-bottom: 2px;
-}
-td:nth-child(1), th:nth-child(1) {
-    text-align: center;
+efx-grid {
+    margin: 0 5px 5px;
+    vertical-align: top;
 }
-#table_div {
-    height: 300px;
+#h_scrollbar_host {
+    height: 250px;
 }
 
-
<button id="add_row_btn">Add row</button>
-<button id="rem_row_btn">Remove row</button>
-<i></i>
-<label for="set_row_in">Set row count:</label>
-<input id="set_row_in" type="number" value="6">
+
<button id="wrap_btn1">Wrap 3 rows</button>
+<button id="wrap_btn2">Wrap 4 rows</button>
+<button id="wrap_btn3">Wrap 5 rows</button>
+<button id="wrap_btn4">Disable wrap mode</button>
 <hr>
-<button id="add_col_btn">Add column</button>
-<button id="rem_col_btn">Remove column</button>
-<i></i>
-<label for="set_col_in">Set col count:</label>
-<input id="set_col_in" type="number" value="6">
+<button id="set_btn1">Set Data on the second table</button>
+<button id="set_btn2">Set Data on the third table</button>
+<button id="add_row_btn">Add row</button>
+<button id="remove_row_btn">Remove row</button>
 <hr>
-<button id="row_height_btn1">Compact row height</button>
-<button id="row_height_btn2">Regular row height</button>
-<button id="row_height_btn3">Spacious row height</button>
-<i></i>
-<label for="col_width_in">Set 1st column width:</label>
-<input id="col_width_in" type="number" value="150">
+<button id="add_col_btn">Add Column</button>
+<button id="remove_col_btn">Remove Column</button>
 <hr>
-<div id="table_div"></div>
+<div id="v_scrollbar_host">
+    <div id="h_scrollbar_host">
+        <efx-grid id="grid"></efx-grid>
+    </div>
+</div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -203,238 +173,123 @@ 

Table manipulation

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var rowId = 0; +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { numRows: 10 }); -var tbl = new Table(document.getElementById("table_div"), { - colCount: 4, - rowCount: 7, - cellWidth: 100, - rowHeight: 30, - header: 1 -}); -var cells = tbl.getCellsInColumn(0); -cells.forEach(function(cell) { - cell.textContent = "" + (rowId++); -}); -tbl.getHeader().getCellsInRow(0).forEach(function(cell, idx) { - cell.textContent = "Header " + (idx + 1); -}); -tbl.getHeaderCell(0, 0).textContent = "Row id"; +var configObj = { + sorting: { + sortableColumns: true + }, + defaultColumnOptions: { + minWidth: 24 + }, + columns: [ + {name: fields[0], width: 100, field: fields[0]}, + {name: fields[2], width: 100, field: fields[2], formatType: "number", colorText: true }, + {name: fields[3], width: 100, field: fields[3], formatType: "percent", blinking: true } + ], + staticDataRows: records, + extensions: [ + new RowSelection(), + new ColumnSelection(), + new ColumnResizing(), + new ColumnFitter(), + new ColumnDragging() + ] +}; + +var grid = document.getElementById("grid"); +var mgr = new MultiTableManager(grid); +mgr.setGridConfig(configObj); -document.getElementById("add_row_btn").addEventListener("click", function(e) { - var ary = tbl.addRows(); - var trElem = ary[0]; - var cell = trElem.cells[0]; - cell.textContent = "" + (rowId++); +wrap_btn1.addEventListener("click", function() { + mgr.wrapTable(3); }); -document.getElementById("rem_row_btn").addEventListener("click", function(e) { - tbl.removeRows(1); +wrap_btn2.addEventListener("click", function() { + mgr.wrapTable(4); }); -document.getElementById("set_row_in").addEventListener("change", function(e) { - var rowCount = +e.currentTarget.value; - if(rowCount !== rowCount) { - return; // Cannot process NaN value; - } - tbl.setRowCount(rowCount); +wrap_btn3.addEventListener("click", function() { + mgr.wrapTable(5); }); - -document.getElementById("add_col_btn").addEventListener("click", function(e) { - var colCount = tbl.getColumnCount(); - tbl.addColumns(); - tbl.getHeaderCell(colCount, 0).textContent = "Header " + (colCount + 1); +wrap_btn4.addEventListener("click", function() { + mgr.wrapTable(0); }); -document.getElementById("rem_col_btn").addEventListener("click", function(e) { - tbl.removeColumns(1); +add_row_btn.addEventListener("click", function() { + mgr.insertRow({}); }); -document.getElementById("set_col_in").addEventListener("change", function(e) { - var colCount = +e.currentTarget.value; - if(colCount !== colCount) { - return; // Cannot process NaN value; - } - tbl.setColumnCount(colCount); +remove_row_btn.addEventListener("click", function() { + mgr.removeRow(); }); - -document.getElementById("row_height_btn1").addEventListener("click", function(e) { - tbl.setDefaultRowHeight(24); - tbl.getElement().classList.add("compact"); +add_col_btn.addEventListener("click", function() { + mgr.insertColumn({field: "industry", width: 80}); +}); +remove_col_btn.addEventListener("click", function() { + mgr.removeColumn(mgr.getColumnCount() - 1); }); -document.getElementById("row_height_btn2").addEventListener("click", function(e) { - tbl.setDefaultRowHeight(30); - tbl.getElement().classList.remove("compact"); +set_btn1.addEventListener("click", function() { + randomlySetData(mgr.getTable(1)); }); -document.getElementById("row_height_btn3").addEventListener("click", function(e) { - tbl.setDefaultRowHeight(36); - tbl.getElement().classList.remove("compact"); +set_btn2.addEventListener("click", function() { + randomlySetData(mgr.getTable(2)); }); -document.getElementById("col_width_in").addEventListener("change", function(e) { - var width = +(e.currentTarget.value); - if(!width) { - width = 100; +setInterval(function simulateDataUpdate() { + var tblCount = mgr.getTableCount(); + + for(var i = 0; i < tblCount; ++i) { + if(Math.random() > 0.6) { + randomlySetData(mgr.getTable(i)); + } } - tbl.setColMinWidths(width, 0); -}); -
-

Cell manipulation

-

Table class does not provide APIs for modifying its cells. However, you can get cell elements through various Table APIs.

-

To get a single cell element from the body section of the table, use getCell method.

-

To get all cell elements in a single column from the body section of the table, use getCellsInColumn method.

-

To get all cell elements in a single row from the body section of the table, use getCellsInRow method.

-

To set colSpan or rowSpan on a cell, use spanBlock method

-

Event listeners can be added on Table instance and its sub table (i.e., body section) for all native events. To add an event listener to Table instance, use addEventListener method.

-

The example below shows how to set cell span and get cell position from a mousemove event.

-
html hr {
-    margin: 5px;
-}
-i:empty {
-    padding-left: 20px;
-}
-input[type="number"] {
-    width: 50px;
-}
-td:nth-child(1), th:nth-child(1) {
-    text-align: center;
-}
+}, 500);
 
-#table_div {
-    display: inline-block;
-}
-#msg_ta {
-    height: 260px;
-    width: 150px;
-    vertical-align: top;
+function randomlySetData(tbl) {
+    if(!tbl || !tbl.api) {
+        return;
+    }
+    var rowCount = mgr.getRowCount();
+    for(var i = 0; i < rowCount; ++i) {
+        if(Math.random() > 0.7) {
+            var rowDef = tbl.api.getRowDefinition(i);
+            if(rowDef) {
+                rowDef.setRowData(DataGenerator.generateRecord(fields));
+            }
+        }
+    }
 }
 
-
<button id="span_btn">Span cells</button>
-<button id="reset_btn">Clear cell span</button>
-<hr>
-<span>Starting from:</span>
-<input id="from_col_in" type="number" value="0">
-<input id="from_row_in" type="number" value="0">
-<i></i>
-<span>Span size:</span>
-<input id="col_span_in" type="number" value="2">
-<input id="row_span_in" type="number" value="2">
-<hr>
-<div>
-    <div id="table_div"></div>
-    <textarea id="msg_ta"></textarea>
+

Positioning grids side by side with vertical scrollbar syncronization

+

You can display multiple grids side by side using CSS as shown in the above example. However, it does not work when you want to have a single vertical scrollbar for multiple grids. If normal native scrollbar is used, all rows in a grid have to be displayed and cannot be virtualized. Large number of rows in each grid can introduce performance problem. You can use Grid's scrollbars instead of native scrollbars to enable row virtualization and improve the performance.

+

To link multiple grids together and have only one single vertical scrollbar, use MultiTableManager.synchronizeVScrollbar method. The method requires two elements to host the scrollbars and array of Grid elements. The first element is for hosting Grid vertical scrollbar. The second element is for hosting native horizontal scrollbar and Grid elements. The vertical scrollbar requires separated host element because it has to be float over view and not moved when horizontal scrolling occurs. The setup for element structure is shown below:

+
<div id="v_scrollbar_host">
+    <div id="h_scrollbar_host">
+        <efx-grid></efx-grid>
+        <efx-grid></efx-grid>
+    </div>
 </div>
 
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["id", "companyName", "market", "industry", "CF_LAST"];
-var colCount = fields.length;
-var rowCount = 10;
-var records = DataGenerator.generateRecords(fields, rowCount);
-var tbl = new Table(document.getElementById("table_div"), {
-    colCount: colCount,
-    rowCount: rowCount,
-    rowHeight: 30,
-    header: 1
-});
-tbl.setColumnWidths([50, 140, 90, 190, 90]);
-var cells = tbl.getAllHeaderCells();
-var cell;
-var record;
-cells.forEach(function(cell, idx) {
-    cell.textContent = fields[idx];
-});
-for(var r = 0; r < rowCount; ++r) {
-    record = records[r];
-    cells = tbl.getCellsInRow(r);
-    for(var c = 0; c < colCount; ++c) {
-        cell = cells[c];
-        cell.textContent = record[fields[c]];
-    }
-}
-
-var bodyTbl = tbl.getBody();
-var headTbl = tbl.getHeader();
-bodyTbl.addEventListener("mousemove", onMouseMoveOverBody);
-
-function onMouseMoveOverBody(e) {
-    var colIndex = bodyTbl.getColumnIndex(e);
-    var rowIndex = bodyTbl.getRowIndex(e);
-    var cell = bodyTbl.getCell(colIndex, rowIndex);
-    var cellContent = cell ? cell.textContent : null;
-    
-    var lines = [
-        "Column index: " + colIndex,
-        "Row index: " + rowIndex,
-        "Cell content: " + cellContent
-    ];
-    msg_ta.value = lines.join("\n");
+

The height for the grid can be specified on the vertical scrollbar host. If so, make sure that the height of horizontal scrollbar host is set to 100%. The width of the grid can be set on the element itself or on every column of the grid.

+

Side by side Grids Example

+
efx-grid+efx-grid {
+    margin-left: 5px;
 }
-
-var fromColIn = document.getElementById("from_col_in");
-var fromRowIn = document.getElementById("from_row_in");
-var colSpanIn = document.getElementById("col_span_in");
-var rowSpanIn = document.getElementById("row_span_in");
-document.getElementById("span_btn").addEventListener("click", function(e) {
-    var c1 = +fromColIn.value;
-    var r1 = +fromRowIn.value;
-    
-    var colSpan = +colSpanIn.value;
-    var rowSpan = +rowSpanIn.value;
-    var c2 = c1 + colSpan - 1;
-    var r2 = r1 + rowSpan - 1;
-    
-    tbl.spanBlock(c1, c2, r1, r2);
-});
-document.getElementById("reset_btn").addEventListener("click", function(e) {
-    var c1 = +fromColIn.value;
-    var r1 = +fromRowIn.value;
-    tbl.spanBlock(c1, c1, r1, r1);
-});
-
-

QuoteLine example

-

You are free to customize the table in any way you like. Table class is just a utility that helps you create HTML table and provide some APIs for accessing some part of the table.

-
html hr {
-    margin: 5px;
-}
-#table_div {
-    display: inline-block;
-}
-
-td.no-border-right, .no-border-right td {
-    border-right-width: 0;
-}
-td.no-border-left, .no-border-left td {
-    border-left-width: 0;
-}
-
-.big-font {
-    font-size: 2em;
-}
-.big-font td {
-    padding-top: 0;
-    padding-bottom: 0;
-}
-.blue-font-color {
-    color: #7777FF;
-}
-.red-font-color {
-    color: red;
-}
-.red-bg-color {
-    background-color: red;
+#v_scrollbar_host {
+    height: 300px;
 }
-.green-font-color {
-    color: green;
+#h_scrollbar_host {
+    height: 100%;
 }
-.align-center {
-    text-align: center;
+#grid_2 {
+    width: 500px;
 }
 
-
<div id="table_div"></div>
+
<div id="v_scrollbar_host">
+    <div id="h_scrollbar_host">
+        <efx-grid id="grid_1"></efx-grid>
+        <efx-grid id="grid_2"></efx-grid>
+    </div>
+</div>
+<hr>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -445,159 +300,70 @@ 

Table manipulation

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var tbl = new Table(table_div, { - colCount: 9, - rowCount: 8, - cellWidth: 100, - rowHeight: 30, - header: 1 -}); -tbl.setColMinWidths(30, 6); -tbl.setColMinWidths(110, 7); -tbl.setColMinWidths(110, 8); -var cellTexts = [ - ["", "GBP=", "", "", "", "1.1926", "/", "1.1930", "0.71%"], - ["UK Pound Sterling/US Dollar FX Spot Rate", "", "", "", "", "SANTANDER", "", "HKG", "SAHK"], - ["Change Summary", "", "Daily View", "", "", "Weekly", "", "Monthly", "Yearly"], - ["MTD %", "-0.78 %", "O", 1.1843, "High", 1.2065, "", 1.2088, 1.2447], - ["3M %", "-2.68 %", "H", 1.1936, "H Date", "01-Mar-2023", "", "01-Mar-2023", "23-Jan-2023"], - ["6M %", "2.93 %", "L", 1.1832, "Low ", 1.1805, "", 1.1805, 1.1805], - ["YTD %", "1.41 %", "C", 1.1842, "L Date", "08-Mar-2023", "", "08-Mar-2023", "08-Mar-2023"], - ["Latest Trade", "", "09-Mar-2023 15:33", "", "", "", "", "", ""] -]; - -hideMiddleBorders(0, 1); -hideMiddleBorders(2, 3); -hideMiddleBorders(4, 5); - -spanColumn(1, 0, 3); -spanColumn(2, 0, 1); -spanColumn(2, 2, 3); -spanColumn(7, 0, 1); -spanColumn(7, 2, 5); +var gen = DataGenerator; +var fields = ["companyName","percent", "number_2", "bid", "ask"]; -tbl.getRow(0).classList.add("big-font"); -tbl.getRow(2).classList.add("blue-font-color"); +var records1 = gen.generateRecords(fields, {seed: 1, rowCount: 20}); +var records2 = gen.generateRecords(fields, {seed: 100, rowCount: 20}); -tbl.getCellsInColumn(6).forEach(addClass.bind(null, "align-center")); -tbl.getCellsInColumn(0).slice(2).forEach(addClass.bind(null, "blue-font-color")); -tbl.getCellsInColumn(2).slice(2).forEach(addClass.bind(null, "blue-font-color")); -tbl.getCellsInColumn(4).slice(2).forEach(addClass.bind(null, "blue-font-color")); +var configObj1 = { + defaultColumnOptions: { + width: 100 + }, + sorting: { + initialSort: { + colIndex: 3, + sortOrder: "d" + } + }, + columns: [ + {name: fields[0], field: fields[0], width: 120}, + {name: fields[1], field: fields[1]}, + {name: fields[2], field: fields[2], colorText: true}, + {name: "Bid", field: "bid"} + ], + staticDataRows: records1 +}; +var configObj2 = { + sorting: { + initialSort: { + colIndex: 0, + sortOrder: "a" + } + }, + columns: [ + {name: "Ask", field: "ask"}, + {name: fields[2], field: fields[2], colorText: true}, + {name: fields[1], field: fields[1]}, + {name: fields[0], field: fields[0]} + ], + staticDataRows: records2 +}; -addClass("red-font-color", tbl.getCell(1, 3)); -addClass("red-font-color", tbl.getCell(1, 4)); -addClass("green-font-color", tbl.getCell(1, 5)); -addClass("green-font-color", tbl.getCell(1, 6)); -tbl.getCellsInRow(0).slice(5, 8).forEach(addClass.bind(null, "green-font-color")); - -var colCount = tbl.getColumnCount(); -var rowCount = tbl.getRowCount(); -for(var r = 0; r < rowCount; ++r) { - var rowText = cellTexts[r]; - for(var c = 0; c < colCount; ++c) { - var cellText = rowText[c]; - var cell = tbl.getCell(c, r); - cell.textContent = cellText; - } -} +var grid1 = document.getElementById("grid_1"); +var grid2 = document.getElementById("grid_2"); -var newsIcon = document.createElement("ef-icon"); -newsIcon.icon = "news"; -addClass("blue-font-color", newsIcon); -tbl.getCell(0, 0).appendChild(newsIcon); +grid1.config = configObj1; +grid2.config = configObj2; -var downIcon = document.createElement("ef-icon"); -downIcon.icon = "hollow-arrow-down"; -addClass("red-font-color", downIcon); -tbl.getCell(2, 0).appendChild(downIcon); - -addClass("red-bg-color", tbl.getCell(8, 0)); - -function spanColumn(rowIndex, c1, c2) { - tbl.spanBlock(c1, c2, rowIndex, rowIndex); -} -function hideMiddleBorders(c1, c2) { - var rowCount = tbl.getRowCount(); - for(var r = 0; r < rowCount; ++r) { - var cell1 = tbl.getCell(c1, r); - var cell2 = tbl.getCell(c2, r); - cell1.classList.add("no-border-right"); - cell2.classList.add("no-border-left"); - } -} -function addClass(classStr, elem) { - elem.classList.add(classStr); -} +MultiTableManager.synchronizeVScrollbar( + document.getElementById("v_scrollbar_host"), + document.getElementById("h_scrollbar_host"), + [grid1, grid2] +);
-

Table API Reference

-

Table(elemopt, optionsopt)

Type Definitions

-
typedef

Options

Options for Table initialization
Type:
Object
Properties:
Name Type Attributes Default Description
colCount number <optional>
0 Number of columns
rowCount number <optional>
0 Number of rows in content table (tbody)
cellWidth number <optional>
Default cell width of each column
cellHeight number <optional>
Default cell height of each row
width number <optional>
Total width of the table. If it is specified, it will override cellWidth
height number <optional>
Total height of the table. If it is specified, it will override cellHeight
header number <optional>
0 Number of header rows
footer number <optional>
0 Number of footer rows

Methods

-
function

addColumns(countopt) → {Array.<Element>}

Parameters:
count
number
<optional>
[default: 1]
Returns:
Array.<Element>
Array of col elements (not td or cell)
-
function

addFooterRows(opt_countopt) → {Array.<Element>}

Parameters:
opt_count
number
<optional>
Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
-
function

addHeaderRows(opt_countopt) → {Array.<Element>}

Parameters:
opt_count
number
<optional>
Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
-
function

addListener(obj, type)

A shorthand to retrieve function from an object and add it as an Eventlistener
Parameters:
obj
Object
Object that contains a handler with the same name as the given `type`
type
string
Event name
Inherited From:
EventDispatcher#addListener
Example:
let obj = {"mouseUp": function(e) { console.log(e); }};
-plugin.addListener(obj, "mouseUp");
-plugin.addListener(obj, "mouseDown");
-
function

addRows(countopt) → {Array.<Element>}

Parameters:
count
number
<optional>
[default: 1]
Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
-
function

cloak(tblElem)

This will change size of the table
Parameters:
tblElem
Element
-
function

distributeColumnWidth()

Distribute columns based on their textContent length
-
function

fixateTableWidth(opt_boolopt)

Try to make table to have fixed size. Table may not have a fixed size, if one of its column has no width (dynamic width).
Parameters:
opt_bool
boolean
<optional>
-
function

getAllCells() → {Array.<Element>}

Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
-
function

getAllFooterCells() → {Array.<Element>}

Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
-
function

getAllHeaderCells() → {Array.<Element>}

Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
-
function

getAllRows() → {Array.<Element>}

Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
-
function

getBody() → {SubTable}

Returns:
-
function

getBoundingClientRect() → {Object}

Returns:
Object
-
function

getCell(c, r) → {Element}

Parameters:
c
number
r
number
Returns:
Element
-
function

getCellPosition(cell, ret_objopt) → {Object}

Parameters:
cell
Element
ret_obj
Object
<optional>
Returns:
Object
Object with x and y property
-
function

getCellsInColumn(c) → {Array.<Element>}

Parameters:
c
number
Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
-
function

getCellsInRow(r) → {Array.<Element>}

Parameters:
r
number
Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
-
function

getCellTextContent(c, r) → {string}

Parameters:
c
number
r
number
Returns:
string
+

MultiTableManager API Reference

+

MultiTableManager(gridElem)

Methods

+
function

synchronizeVScrollbar(vScrollbarHost, hScrollbarHost, gridElems) → {Promise.<Array>}

Parameters:
vScrollbarHost
Element
Host element for the vertical scrollbar.
hScrollbarHost
Element
Host element for the horizontal scrollbar. This element must be a child of the vScrollbarHost element.
gridElems
Array.<Element>
Array of grid elements. The first element will be treated as primary grid.
Returns:
Promise.<Array>
+
function

dispose()

function

getColumnCount() → {number}

Returns:
number
-
function

getColumnIndex(e) → {number}

Parameters:
e
Event
Returns:
number
-
function

getColumnLeft(colIndex, rowIndexopt) → {number}

Parameters:
colIndex
number
rowIndex
number
<optional>
Returns:
number
-
function

getColumnTextContent(c) → {string}

Parameters:
c
number
Returns:
string
-
function

getDefaultColumnWidth() → {number|null}

Returns:
number | null
-
function

getDefaultRowHeight() → {number|null}

Returns:
number | null
-
function

getElement() → {Element}

Inherited From:
ElementWrapper#getElement
Returns:
Element
-
function

getFooter() → {SubTable}

Returns:
-
function

getFooterCell(c, r) → {Element}

Parameters:
c
number
r
number
Returns:
Element
-
function

getHeader() → {SubTable}

Returns:
-
function

getHeaderCell(c, r) → {Element}

Parameters:
c
number
r
number
Returns:
Element
-
function

getListener(type, idxopt) → {function}

Get event listener (function handler) from the specified event.
Parameters:
type
string
Event name
idx
number
<optional>
[default: 0]
Index of the listener to be retrieved. This is used when there are multiple event listeners
Inherited From:
EventDispatcher#getListener
Returns:
function
-
function

getMousePosition(e, retObjopt) → {Object}

Get mouse position relative to this element
Parameters:
e
Event
MouseEvent should be given
retObj
Object
<optional>
Returns:
Object
-
function

getRow(r) → {Element}

Parameters:
r
number
Returns:
Element
Array of tr (HTMLTableRowElement) elements
function

getRowCount() → {number}

Returns:
number
-
function

getRowIndex(e) → {number}

Parameters:
e
Event
Returns:
number
-
function

getRows() → {Array.<Element>}

Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
-
function

getRowTextContent(r) → {string}

Parameters:
r
number
Returns:
string
-
function

getRowTop(rowRef) → {number}

Parameters:
rowRef
number | Element
Returns:
number
-
function

getTableElement() → {Element}

Returns:
Element
-
function

getTableTextContent() → {string}

Returns:
string
-
function

getTextContents() → {Array.<Array.<string>>}

Returns:
Array.<Array.<string>>
-
function

hasListener(type) → {boolean}

Check whether the specified event has a function handler.
Parameters:
type
string
Event name
Inherited From:
EventDispatcher#hasListener
Returns:
boolean
-
function

init(options)

Parameters:
options
-
function

log(opt_rowLimitopt) → {Array.<Object>}

Parameters:
opt_rowLimit
number
<optional>
Returns:
Array.<Object>
Array of rows that just log in console
-
function

loosenTableWidth(opt_boolopt)

Parameters:
opt_bool
boolean
<optional>
-
function

removeAllColumns()

-
function

removeAllEventListeners()

Remove all function handlers from all events.
-
function

removeAllRows()

-
function

removeColumns(opt_countopt)

Parameters:
opt_count
number
<optional>
-
function

removeFooterRows(opt_countopt)

Parameters:
opt_count
number
<optional>
-
function

removeHeaderRows(opt_countopt)

Parameters:
opt_count
number
<optional>
-
function

removeRows(countopt)

Parameters:
count
number
<optional>
Number of rows to be removed. If count is not specified, all rows are removed
-
function

setCellSize(defaultWidth, defaultHeight)

Parameters:
defaultWidth
number
defaultHeight
number
-
function

setColBackgroundColors(val, colIndexopt)

Parameters:
val
string | Array.<string>
colIndex
number
<optional>
Column index
-
function

setColBGColors(val, colIndexopt)

Parameters:
val
string | Array.<string>
colIndex
number
<optional>
Column index
-
function

setColBorders(val, colIndexopt)

Parameters:
val
number | string | Array.<(number|string)>
colIndex
number
<optional>
Column index
-
function

setColMinWidths(val, colIndexopt)

Parameters:
val
number | string | Array.<(string|number)>
colIndex
number
<optional>
Column index
-
function

setColumnCount(val)

Parameters:
val
number
-
function

setColumnWidths(val, colIndexopt)

Parameters:
val
number | string | Array.<(string|number)>
colIndex
number
<optional>
Column index
-
function

setCRWH(col, row, width, height)

Parameters:
col
number
row
number
width
number
height
number
-
function

setDefaultColumnWidth(valopt)

Parameters:
val
number | null
<optional>
-
function

setDefaultRowHeight(valopt)

Parameters:
val
number | null
<optional>
-
function

setParent(parent)

Parameters:
parent
Inherited From:
ElementWrapper#setParent
-
function

setRowCount(val)

Parameters:
val
number
-
function

setSize(width, height)

Parameters:
width
number
height
number
-
function

spanBlock(c1, c2, r1, r2) → {Element}

Parameters:
c1
number
Starting column index
c2
number
Destination column index
r1
number
Starting row index
r2
number
Destination row index
Returns:
Element
Top left cell element
-
function

spanHorizontally(r, bool) → {Element}

Horizontally span the cell from the first column to cover the entire row. This is useful for creating header row
Parameters:
r
number
bool
boolean
Returns:
Element
Top left cell element
\ No newline at end of file +
function

getTable(atopt) → {Element}

Parameters:
at
number
<optional>
Returns:
Element
+
function

getTableCount() → {number}

Returns:
number
+
function

insertColumn(columnOption, idxopt)

Parameters:
columnOption
*
String will be treated as field, while object is treated as the column options
idx
number
<optional>
+
function

insertRow(rowOptionopt, atopt)

Parameters:
rowOption
Object
<optional>
at
number
<optional>
+
function

removeColumn(colRef)

Parameters:
colRef
*
Column reference
+
function

removeRow(atopt)

Parameters:
at
number
<optional>
+
function

setGridConfig(configObjopt)

Parameters:
configObj
Object
<optional>
+
function

setTableCount(num)

Parameters:
num
number
Number of tables. Number cannot be less than one.
+
function

wrapTable(rowCount)

Parameters:
rowCount
number
Number of row per table. Set number to zero to turn off wrap mode.
\ No newline at end of file diff --git a/template-150.html b/template-150.html index 5757034b..e30678b5 100644 --- a/template-150.html +++ b/template-150.html @@ -1,53 +1,198 @@ -

Printing

-

You can print Grid using the Printing Utility or the native printer feature within a browser. The native printer is more difficult to use, however.

-

Using a native printer

-

Since content can scroll inside Grid, native printers do not work well with it, as the final print preview truncates any components that are not currently visible on the screen.

-

To solve this, you need to update the grid's configuration to show all hidden information before you preview it. See the steps below.

-

1. Initialize Grid

-
var config = {
-  // ... See column options for available options
-};
-
-var grid = document.getElementById("grid");
-grid.config = config;
-
-

2. Adjust the Grid's resolution

-

Adjust the Grid's resolution to reflect the paper size (for example, A3, A4, A5).

+

Native HTML table

+

Sometimes you only need a simple table for your app. Native HTML table could be used in place of Grid component for quick and easy table layout. The main advantages of native HTML table is simplicity, flexibility, and style customization. However, manipulating HTML element directly could be tedious and cumbersome. Table class from our utility package can help managing native HTML table with ease.

-

@media print CSS properties cannot be used to adjust Grid's style, as Grid will not re-render itself with CSS properties. They can only be used to adjust the layout before the print preview.

+

Note that Table class only provides JavaScript logic for HTML element manipulation. Styles and CSS are not provided by Grid utility package.

-
function beforePrint() {
-  grid.style.width = "180mm"; // A4 width
-  grid.style.height = "unset";
+

Usage

+

Table class is located in the utility package as shown in the code snippet below:

+
import {Table} from "@refinitiv-ui/efx-grid/utils";
+
+var tableInstance = new Table(divElement, {
+    colCount: 4,
+    rowCount: 5
+});
+
+
table td {
+    text-align: center;
 }
 
-

3. Delayed window.print

-

Grid needs approximately 300ms to recalculate and re-render itself. So you need to make sure Grid has enough time to update its state before the print preview appears.

-
function print() {
-  beforePrint();
-  setTimeout(function () {
-    window.print();
-  }, 500); // Grid needs at least 300ms  to recalculate and repaint itself.
+
<div id="table_div">
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var tableInstance = new Table(table_div, {
+    colCount: 4,
+    rowCount: 5
+});
+
+var rowCount = tableInstance.getRowCount();
+for(var r = 0; r < rowCount; ++r) {
+    tableInstance.getCellsInRow(r).forEach(function(cell, colIndex) {
+        cell.textContent = ([colIndex, r]).join(", ");
+    });
 }
 
-

4. After printing

-

Lastly, the grid's configuration needs to be restored to its initial state. For this, the window.onafterprint hook will be triggered once printing is finished.

-
window.onafterprint = function () {
-  grid.style.width = "100%";
-  grid.style.height = "500px";
+

Table initialization

+

Table class takes two parameters for its constructor. The first parameter is a placeholder element. It is used for positioning the table in the HTML document. The second parameter is a table configuration object, where you can define various parameters and options (e.g., number of columns, number of rows, width, height). For all available options, see Table API Reference section.

+
html hr {
+    margin-top: 5px;
+    margin-bottom: 10px;
 }
 
-

Using the Printing Utility

-

Unlike the native printer above, the Printing Utility has been created to help print the grid without other components. Rows and columns will not be truncated when using the utility.

-

Basically, the utility creates a new grid DOM dynamically and copies its data into this newly created grid. It will be destroyed automatically when printing is finished.

-
efx-grid {
+
<big>Table with default column size</big>
+<div id="table_div1"></div>
+<hr>
+<big>Table with fixed column size and header section</big>
+<div id="table_div2"></div>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var tableDiv1 = document.getElementById("table_div1");
+var tbl1 = new Table(tableDiv1, {
+    colCount: 4,
+    rowCount: 5,
+    cellHeight: 30
+});
+var tableDiv2 = document.getElementById("table_div2");
+var tbl2 = new Table(tableDiv2, {
+    colCount: 4,
+    rowCount: 5,
+    cellWidth: 100,
+    cellHeight: 30,
+    header: 1
+});
+tbl2.getHeader().getCellsInRow(0).forEach(function(cell, idx) {
+    cell.textContent = "Header " + (idx + 1);
+});
+
+

Table structure

+

Table class generates HTML elements and table structure based on the given configuration. The general structure created by the class will look like the code snippet below:

+
<div>
+    <table>
+        <colgroup>
+            <col>
+            ...
+        </colgroup>
+        <thead>
+            <tr>
+                <th></th>
+                ...
+            <tr>
+            ...
+        </thead>
+        <tbody>
+            <tr>
+                <td></td>
+                ...
+            </tr>
+            ...
+        </tbody>
+    </table>
+</div>
+
+

Table class instance itself represent the placeholder element (root element) and not the table element. The table below shows how to get corresponding element from the Table instance.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ElementAPI
Placeholder elementTable.getElement()
tableTable.getTableElement()
tbodyTable.getBody().getElement()
theadTable.getHeader().getElement()
tfootTable.getFooter().getElement()
trTable.getRow(r), Table.getBody().getRow(r)
td (tbody)Table.getCell(c, r), Table.getBody().getCell(c, r)
th (thead)Table.getHeaderCell(c, r), Table.getHeader().getCell(c, r)
td (tfoot)Table.getFooterCell(c, r), Table.getFooter().getCell(c, r)
+

Table manipulation

+

With Table class, you can add and remove rows and columns at runtime. For changing content and styles, you need to retrieve the element from Table instance, and then manipulate the element properties directly.

+

To change number of rows, use addRows and removeRows methods.

+

To change number of columns, use addColumns and removeColumns methods.

+

The example below also shows how to change row height of each row in the table.

+
html hr {
+    margin: 5px;
+}
+i:empty {
+    padding-left: 20px;
+}
+.compact td, .compact th {
+    padding-top: 2px;
+    padding-bottom: 2px;
+}
+td:nth-child(1), th:nth-child(1) {
+    text-align: center;
+}
+#table_div {
     height: 300px;
 }
 
-
<button id="print">print</button>
-<efx-grid id="grid"></efx-grid>
+
<button id="add_row_btn">Add row</button>
+<button id="rem_row_btn">Remove row</button>
+<i></i>
+<label for="set_row_in">Set row count:</label>
+<input id="set_row_in" type="number" value="6">
+<hr>
+<button id="add_col_btn">Add column</button>
+<button id="rem_col_btn">Remove column</button>
+<i></i>
+<label for="set_col_in">Set col count:</label>
+<input id="set_col_in" type="number" value="6">
+<hr>
+<button id="row_height_btn1">Compact row height</button>
+<button id="row_height_btn2">Regular row height</button>
+<button id="row_height_btn3">Spacious row height</button>
+<i></i>
+<label for="col_width_in">Set 1st column width:</label>
+<input id="col_width_in" type="number" value="150">
+<hr>
+<div id="table_div"></div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -58,54 +203,401 @@ 

Using the Printing Utility

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "icon"]; -DataGenerator.addFieldInfo("icon", { - type: "set", - members: ["up", "down", "phone", "calendar", "flame"] -}); -var records = DataGenerator.generateRecords(fields, { numRows: 20 }); -var configObj = { - columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80}, - {name: "Net. Chng", field: fields[3], width: 80}, - {name: "Industry", field: fields[4]}, - {name: "Icon", field: fields[5], binding: EFIconFormatter.create()} - ], - staticDataRows: records -}; - -var grid = document.getElementById("grid"); -grid.config = configObj; - -document.getElementById("print").addEventListener("click", function() { - GridPrinter.print(grid); - }); -
-

First, install package from npm.

-
npm install @refinitiv-ui/efx-grid
-
-

Then, use import syntax for importing the utility into your app.

-
import { GridPrinter } from "@refinitiv-ui/efx-grid/utils";
-
-

Finally, send Grid into the GridPrinter utility.

-
var config = {
-    // ... See column options for available options
-};
-
-var grid = document.getElementById("grid");
-grid.config = config;
-
-GridPrinter.print(grid);
-
-

GridPrinter API Reference

-

GridPrinter

Type Definitions

-
typedef

Options

Configuration object for customizing priting behavior can be passed through `GridPrinter.setPrintOptions` method
Type:
Object
Properties:
Name Type Attributes Description
pageWidth number <optional>
Paper width in pixel. This limits number of columns to be shown on a single page
pageHeight number <optional>
Paper height in pixel. This limits number of rows to be shown on a single page
primaryColumn number <optional>
Column index that will be placed as the first column on each page.

Methods

-
function

createPrintElement(grid, optionsopt) → {Element}

Parameters:
grid
*
grid element, currently supports efx-grid, emerald-grid, tr.CompositeGrid, rt.Grid and Core
options
Object
<optional>
Returns:
Element
-
function

enableDebugMode(boolopt)

Parameters:
bool
boolean
<optional>
-
function

getPreFlightInfo(grid, optionsopt) → {Object}

Parameters:
grid
tr.Grid
options
Object
<optional>
Returns:
Object
-
function

observe(iFrameElementopt)

Parameters:
iFrameElement
HTMLIFrameElement
<optional>
If not specified, current window is used instead. Specify null to un-observe existing window object.
-
function

print(grid)

Parameters:
grid
*
grid element, currently supports efx-grid, efx-grid, emerald-grid, tr.CompositeGrid, rt.Grid and Core
-
function

setPrintOptions(options)

Parameters:
options
GridPrinter.Options
-
function

unobserve()

\ No newline at end of file +var rowId = 0; + +var tbl = new Table(document.getElementById("table_div"), { + colCount: 4, + rowCount: 7, + cellWidth: 100, + rowHeight: 30, + header: 1 +}); +var cells = tbl.getCellsInColumn(0); +cells.forEach(function(cell) { + cell.textContent = "" + (rowId++); +}); +tbl.getHeader().getCellsInRow(0).forEach(function(cell, idx) { + cell.textContent = "Header " + (idx + 1); +}); +tbl.getHeaderCell(0, 0).textContent = "Row id"; + +document.getElementById("add_row_btn").addEventListener("click", function(e) { + var ary = tbl.addRows(); + var trElem = ary[0]; + var cell = trElem.cells[0]; + cell.textContent = "" + (rowId++); +}); +document.getElementById("rem_row_btn").addEventListener("click", function(e) { + tbl.removeRows(1); +}); +document.getElementById("set_row_in").addEventListener("change", function(e) { + var rowCount = +e.currentTarget.value; + if(rowCount !== rowCount) { + return; // Cannot process NaN value; + } + tbl.setRowCount(rowCount); +}); + +document.getElementById("add_col_btn").addEventListener("click", function(e) { + var colCount = tbl.getColumnCount(); + tbl.addColumns(); + tbl.getHeaderCell(colCount, 0).textContent = "Header " + (colCount + 1); +}); +document.getElementById("rem_col_btn").addEventListener("click", function(e) { + tbl.removeColumns(1); +}); +document.getElementById("set_col_in").addEventListener("change", function(e) { + var colCount = +e.currentTarget.value; + if(colCount !== colCount) { + return; // Cannot process NaN value; + } + tbl.setColumnCount(colCount); +}); + +document.getElementById("row_height_btn1").addEventListener("click", function(e) { + tbl.setDefaultRowHeight(24); + tbl.getElement().classList.add("compact"); +}); +document.getElementById("row_height_btn2").addEventListener("click", function(e) { + tbl.setDefaultRowHeight(30); + tbl.getElement().classList.remove("compact"); +}); +document.getElementById("row_height_btn3").addEventListener("click", function(e) { + tbl.setDefaultRowHeight(36); + tbl.getElement().classList.remove("compact"); +}); + +document.getElementById("col_width_in").addEventListener("change", function(e) { + var width = +(e.currentTarget.value); + if(!width) { + width = 100; + } + tbl.setColMinWidths(width, 0); +}); +
+

Cell manipulation

+

Table class does not provide APIs for modifying its cells. However, you can get cell elements through various Table APIs.

+

To get a single cell element from the body section of the table, use getCell method.

+

To get all cell elements in a single column from the body section of the table, use getCellsInColumn method.

+

To get all cell elements in a single row from the body section of the table, use getCellsInRow method.

+

To set colSpan or rowSpan on a cell, use spanBlock method

+

Event listeners can be added on Table instance and its sub table (i.e., body section) for all native events. To add an event listener to Table instance, use addEventListener method.

+

The example below shows how to set cell span and get cell position from a mousemove event.

+
html hr {
+    margin: 5px;
+}
+i:empty {
+    padding-left: 20px;
+}
+input[type="number"] {
+    width: 50px;
+}
+td:nth-child(1), th:nth-child(1) {
+    text-align: center;
+}
+
+#table_div {
+    display: inline-block;
+}
+#msg_ta {
+    height: 260px;
+    width: 150px;
+    vertical-align: top;
+}
+
+
<button id="span_btn">Span cells</button>
+<button id="reset_btn">Clear cell span</button>
+<hr>
+<span>Starting from:</span>
+<input id="from_col_in" type="number" value="0">
+<input id="from_row_in" type="number" value="0">
+<i></i>
+<span>Span size:</span>
+<input id="col_span_in" type="number" value="2">
+<input id="row_span_in" type="number" value="2">
+<hr>
+<div>
+    <div id="table_div"></div>
+    <textarea id="msg_ta"></textarea>
+</div>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["id", "companyName", "market", "industry", "CF_LAST"];
+var colCount = fields.length;
+var rowCount = 10;
+var records = DataGenerator.generateRecords(fields, rowCount);
+var tbl = new Table(document.getElementById("table_div"), {
+    colCount: colCount,
+    rowCount: rowCount,
+    rowHeight: 30,
+    header: 1
+});
+tbl.setColumnWidths([50, 140, 90, 190, 90]);
+var cells = tbl.getAllHeaderCells();
+var cell;
+var record;
+cells.forEach(function(cell, idx) {
+    cell.textContent = fields[idx];
+});
+for(var r = 0; r < rowCount; ++r) {
+    record = records[r];
+    cells = tbl.getCellsInRow(r);
+    for(var c = 0; c < colCount; ++c) {
+        cell = cells[c];
+        cell.textContent = record[fields[c]];
+    }
+}
+
+var bodyTbl = tbl.getBody();
+var headTbl = tbl.getHeader();
+bodyTbl.addEventListener("mousemove", onMouseMoveOverBody);
+
+function onMouseMoveOverBody(e) {
+    var colIndex = bodyTbl.getColumnIndex(e);
+    var rowIndex = bodyTbl.getRowIndex(e);
+    var cell = bodyTbl.getCell(colIndex, rowIndex);
+    var cellContent = cell ? cell.textContent : null;
+    
+    var lines = [
+        "Column index: " + colIndex,
+        "Row index: " + rowIndex,
+        "Cell content: " + cellContent
+    ];
+    msg_ta.value = lines.join("\n");
+}
+
+var fromColIn = document.getElementById("from_col_in");
+var fromRowIn = document.getElementById("from_row_in");
+var colSpanIn = document.getElementById("col_span_in");
+var rowSpanIn = document.getElementById("row_span_in");
+document.getElementById("span_btn").addEventListener("click", function(e) {
+    var c1 = +fromColIn.value;
+    var r1 = +fromRowIn.value;
+    
+    var colSpan = +colSpanIn.value;
+    var rowSpan = +rowSpanIn.value;
+    var c2 = c1 + colSpan - 1;
+    var r2 = r1 + rowSpan - 1;
+    
+    tbl.spanBlock(c1, c2, r1, r2);
+});
+document.getElementById("reset_btn").addEventListener("click", function(e) {
+    var c1 = +fromColIn.value;
+    var r1 = +fromRowIn.value;
+    tbl.spanBlock(c1, c1, r1, r1);
+});
+
+

QuoteLine example

+

You are free to customize the table in any way you like. Table class is just a utility that helps you create HTML table and provide some APIs for accessing some part of the table.

+
html hr {
+    margin: 5px;
+}
+#table_div {
+    display: inline-block;
+}
+
+td.no-border-right, .no-border-right td {
+    border-right-width: 0;
+}
+td.no-border-left, .no-border-left td {
+    border-left-width: 0;
+}
+
+.big-font {
+    font-size: 2em;
+}
+.big-font td {
+    padding-top: 0;
+    padding-bottom: 0;
+}
+.blue-font-color {
+    color: #7777FF;
+}
+.red-font-color {
+    color: red;
+}
+.red-bg-color {
+    background-color: red;
+}
+.green-font-color {
+    color: green;
+}
+.align-center {
+    text-align: center;
+}
+
+
<div id="table_div"></div>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var tbl = new Table(table_div, {
+    colCount: 9,
+    rowCount: 8,
+    cellWidth: 100,
+    rowHeight: 30,
+    header: 1
+});
+tbl.setColMinWidths(30, 6);
+tbl.setColMinWidths(110, 7);
+tbl.setColMinWidths(110, 8);
+var cellTexts = [
+    ["", "GBP=", "", "", "", "1.1926", "/", "1.1930", "0.71%"],
+    ["UK Pound Sterling/US Dollar FX Spot Rate", "", "", "", "", "SANTANDER", "", "HKG", "SAHK"],
+    ["Change Summary", "", "Daily View", "", "", "Weekly", "", "Monthly", "Yearly"],
+    ["MTD %", "-0.78 %", "O", 1.1843, "High", 1.2065, "", 1.2088, 1.2447],
+    ["3M %", "-2.68 %", "H", 1.1936, "H Date", "01-Mar-2023", "", "01-Mar-2023", "23-Jan-2023"],
+    ["6M %", "2.93 %", "L", 1.1832, "Low ", 1.1805, "", 1.1805, 1.1805],
+    ["YTD %", "1.41 %", "C", 1.1842, "L Date", "08-Mar-2023", "", "08-Mar-2023", "08-Mar-2023"],
+    ["Latest Trade", "", "09-Mar-2023 15:33", "", "", "", "", "", ""]
+];
+
+hideMiddleBorders(0, 1);
+hideMiddleBorders(2, 3);
+hideMiddleBorders(4, 5);
+
+spanColumn(1, 0, 3);
+spanColumn(2, 0, 1);
+spanColumn(2, 2, 3);
+spanColumn(7, 0, 1);
+spanColumn(7, 2, 5);
+
+tbl.getRow(0).classList.add("big-font");
+tbl.getRow(2).classList.add("blue-font-color");
+
+tbl.getCellsInColumn(6).forEach(addClass.bind(null, "align-center"));
+tbl.getCellsInColumn(0).slice(2).forEach(addClass.bind(null, "blue-font-color"));
+tbl.getCellsInColumn(2).slice(2).forEach(addClass.bind(null, "blue-font-color"));
+tbl.getCellsInColumn(4).slice(2).forEach(addClass.bind(null, "blue-font-color"));
+
+addClass("red-font-color", tbl.getCell(1, 3));
+addClass("red-font-color", tbl.getCell(1, 4));
+addClass("green-font-color", tbl.getCell(1, 5));
+addClass("green-font-color", tbl.getCell(1, 6));
+tbl.getCellsInRow(0).slice(5, 8).forEach(addClass.bind(null, "green-font-color"));
+
+var colCount = tbl.getColumnCount();
+var rowCount = tbl.getRowCount();
+for(var r = 0; r < rowCount; ++r) {
+    var rowText = cellTexts[r];
+    for(var c = 0; c < colCount; ++c) {
+        var cellText = rowText[c];
+        var cell = tbl.getCell(c, r);
+        cell.textContent = cellText;
+    }
+}
+
+var newsIcon = document.createElement("ef-icon");
+newsIcon.icon = "news";
+addClass("blue-font-color", newsIcon);
+tbl.getCell(0, 0).appendChild(newsIcon);
+
+var downIcon = document.createElement("ef-icon");
+downIcon.icon = "hollow-arrow-down";
+addClass("red-font-color", downIcon);
+tbl.getCell(2, 0).appendChild(downIcon);
+
+addClass("red-bg-color", tbl.getCell(8, 0));
+
+function spanColumn(rowIndex, c1, c2) {
+    tbl.spanBlock(c1, c2, rowIndex, rowIndex);
+}
+function hideMiddleBorders(c1, c2) {
+    var rowCount = tbl.getRowCount();
+    for(var r = 0; r < rowCount; ++r) {
+        var cell1 = tbl.getCell(c1, r);
+        var cell2 = tbl.getCell(c2, r);
+        cell1.classList.add("no-border-right");
+        cell2.classList.add("no-border-left");
+    }
+}
+function addClass(classStr, elem) {
+    elem.classList.add(classStr);
+}
+
+

Table API Reference

+

Table(elemopt, optionsopt)

Type Definitions

+
typedef

Options

Options for Table initialization
Type:
Object
Properties:
Name Type Attributes Default Description
colCount number <optional>
0 Number of columns
rowCount number <optional>
0 Number of rows in content table (tbody)
cellWidth number <optional>
Default cell width of each column
cellHeight number <optional>
Default cell height of each row
width number <optional>
Total width of the table. If it is specified, it will override cellWidth
height number <optional>
Total height of the table. If it is specified, it will override cellHeight
header number <optional>
0 Number of header rows
footer number <optional>
0 Number of footer rows

Methods

+
function

addColumns(countopt) → {Array.<Element>}

Parameters:
count
number
<optional>
[default: 1]
Returns:
Array.<Element>
Array of col elements (not td or cell)
+
function

addFooterRows(opt_countopt) → {Array.<Element>}

Parameters:
opt_count
number
<optional>
Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
+
function

addHeaderRows(opt_countopt) → {Array.<Element>}

Parameters:
opt_count
number
<optional>
Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
+
function

addListener(obj, type)

A shorthand to retrieve function from an object and add it as an Eventlistener
Parameters:
obj
Object
Object that contains a handler with the same name as the given `type`
type
string
Event name
Inherited From:
EventDispatcher#addListener
Example:
let obj = {"mouseUp": function(e) { console.log(e); }};
+plugin.addListener(obj, "mouseUp");
+plugin.addListener(obj, "mouseDown");
+
function

addRows(countopt) → {Array.<Element>}

Parameters:
count
number
<optional>
[default: 1]
Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
+
function

cloak(tblElem)

This will change size of the table
Parameters:
tblElem
Element
+
function

distributeColumnWidth()

Distribute columns based on their textContent length
+
function

fixateTableWidth(opt_boolopt)

Try to make table to have fixed size. Table may not have a fixed size, if one of its column has no width (dynamic width).
Parameters:
opt_bool
boolean
<optional>
+
function

getAllCells() → {Array.<Element>}

Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
+
function

getAllFooterCells() → {Array.<Element>}

Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
+
function

getAllHeaderCells() → {Array.<Element>}

Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
+
function

getAllRows() → {Array.<Element>}

Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
+
function

getBody() → {SubTable}

Returns:
+
function

getBoundingClientRect() → {Object}

Returns:
Object
+
function

getCell(c, r) → {Element}

Parameters:
c
number
r
number
Returns:
Element
+
function

getCellPosition(cell, ret_objopt) → {Object}

Parameters:
cell
Element
ret_obj
Object
<optional>
Returns:
Object
Object with x and y property
+
function

getCellsInColumn(c) → {Array.<Element>}

Parameters:
c
number
Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
+
function

getCellsInRow(r) → {Array.<Element>}

Parameters:
r
number
Returns:
Array.<Element>
Array of td (HTMLTableCellElement) elements
+
function

getCellTextContent(c, r) → {string}

Parameters:
c
number
r
number
Returns:
string
+
function

getColumnCount() → {number}

Returns:
number
+
function

getColumnIndex(e) → {number}

Parameters:
e
Event
Returns:
number
+
function

getColumnLeft(colIndex, rowIndexopt) → {number}

Parameters:
colIndex
number
rowIndex
number
<optional>
Returns:
number
+
function

getColumnTextContent(c) → {string}

Parameters:
c
number
Returns:
string
+
function

getDefaultColumnWidth() → {number|null}

Returns:
number | null
+
function

getDefaultRowHeight() → {number|null}

Returns:
number | null
+
function

getElement() → {Element}

Inherited From:
ElementWrapper#getElement
Returns:
Element
+
function

getFooter() → {SubTable}

Returns:
+
function

getFooterCell(c, r) → {Element}

Parameters:
c
number
r
number
Returns:
Element
+
function

getHeader() → {SubTable}

Returns:
+
function

getHeaderCell(c, r) → {Element}

Parameters:
c
number
r
number
Returns:
Element
+
function

getListener(type, idxopt) → {function}

Get event listener (function handler) from the specified event.
Parameters:
type
string
Event name
idx
number
<optional>
[default: 0]
Index of the listener to be retrieved. This is used when there are multiple event listeners
Inherited From:
EventDispatcher#getListener
Returns:
function
+
function

getMousePosition(e, retObjopt) → {Object}

Get mouse position relative to this element
Parameters:
e
Event
MouseEvent should be given
retObj
Object
<optional>
Returns:
Object
+
function

getRow(r) → {Element}

Parameters:
r
number
Returns:
Element
Array of tr (HTMLTableRowElement) elements
+
function

getRowCount() → {number}

Returns:
number
+
function

getRowIndex(e) → {number}

Parameters:
e
Event
Returns:
number
+
function

getRows() → {Array.<Element>}

Returns:
Array.<Element>
Array of tr (HTMLTableRowElement) elements
+
function

getRowTextContent(r) → {string}

Parameters:
r
number
Returns:
string
+
function

getRowTop(rowRef) → {number}

Parameters:
rowRef
number | Element
Returns:
number
+
function

getTableElement() → {Element}

Returns:
Element
+
function

getTableTextContent() → {string}

Returns:
string
+
function

getTextContents() → {Array.<Array.<string>>}

Returns:
Array.<Array.<string>>
+
function

hasListener(type) → {boolean}

Check whether the specified event has a function handler.
Parameters:
type
string
Event name
Inherited From:
EventDispatcher#hasListener
Returns:
boolean
+
function

init(options)

Parameters:
options
+
function

log(opt_rowLimitopt) → {Array.<Object>}

Parameters:
opt_rowLimit
number
<optional>
Returns:
Array.<Object>
Array of rows that just log in console
+
function

loosenTableWidth(opt_boolopt)

Parameters:
opt_bool
boolean
<optional>
+
function

removeAllColumns()

+
function

removeAllEventListeners()

Remove all function handlers from all events.
+
function

removeAllRows()

+
function

removeColumns(opt_countopt)

Parameters:
opt_count
number
<optional>
+
function

removeFooterRows(opt_countopt)

Parameters:
opt_count
number
<optional>
+
function

removeHeaderRows(opt_countopt)

Parameters:
opt_count
number
<optional>
+
function

removeRows(countopt)

Parameters:
count
number
<optional>
Number of rows to be removed. If count is not specified, all rows are removed
+
function

setCellSize(defaultWidth, defaultHeight)

Parameters:
defaultWidth
number
defaultHeight
number
+
function

setColBackgroundColors(val, colIndexopt)

Parameters:
val
string | Array.<string>
colIndex
number
<optional>
Column index
+
function

setColBGColors(val, colIndexopt)

Parameters:
val
string | Array.<string>
colIndex
number
<optional>
Column index
+
function

setColBorders(val, colIndexopt)

Parameters:
val
number | string | Array.<(number|string)>
colIndex
number
<optional>
Column index
+
function

setColMinWidths(val, colIndexopt)

Parameters:
val
number | string | Array.<(string|number)>
colIndex
number
<optional>
Column index
+
function

setColumnCount(val)

Parameters:
val
number
+
function

setColumnWidths(val, colIndexopt)

Parameters:
val
number | string | Array.<(string|number)>
colIndex
number
<optional>
Column index
+
function

setCRWH(col, row, width, height)

Parameters:
col
number
row
number
width
number
height
number
+
function

setDefaultColumnWidth(valopt)

Parameters:
val
number | null
<optional>
+
function

setDefaultRowHeight(valopt)

Parameters:
val
number | null
<optional>
+
function

setParent(parent)

Parameters:
parent
Inherited From:
ElementWrapper#setParent
+
function

setRowCount(val)

Parameters:
val
number
+
function

setSize(width, height)

Parameters:
width
number
height
number
+
function

spanBlock(c1, c2, r1, r2) → {Element}

Parameters:
c1
number
Starting column index
c2
number
Destination column index
r1
number
Starting row index
r2
number
Destination row index
Returns:
Element
Top left cell element
+
function

spanHorizontally(r, bool) → {Element}

Horizontally span the cell from the first column to cover the entire row. This is useful for creating header row
Parameters:
r
number
bool
boolean
Returns:
Element
Top left cell element
\ No newline at end of file diff --git a/template-151.html b/template-151.html index c31853eb..5757034b 100644 --- a/template-151.html +++ b/template-151.html @@ -1,36 +1,52 @@ -

Column Format Dialog

-

The Column Format Dialog is a user-friendly interface for column display customization. It can format a column's value display from General to Number, Scaled, Percent or Datetime, and so on.

-

Features

-
    -
  • Value formatting: number, scaled, date and time, and FX formats
  • -
  • Heatmap
  • -
  • Conditional coloring
  • -
  • Colored texts and background
  • -
-

Demo

-

Right-click on each column header to see the dialog.

-
textarea {
-    width: 100%;
-    height: 100px;
+

Printing

+

You can print Grid using the Printing Utility or the native printer feature within a browser. The native printer is more difficult to use, however.

+

Using a native printer

+

Since content can scroll inside Grid, native printers do not work well with it, as the final print preview truncates any components that are not currently visible on the screen.

+

To solve this, you need to update the grid's configuration to show all hidden information before you preview it. See the steps below.

+

1. Initialize Grid

+
var config = {
+  // ... See column options for available options
+};
+
+var grid = document.getElementById("grid");
+grid.config = config;
+
+

2. Adjust the Grid's resolution

+

Adjust the Grid's resolution to reflect the paper size (for example, A3, A4, A5).

+
+

@media print CSS properties cannot be used to adjust Grid's style, as Grid will not re-render itself with CSS properties. They can only be used to adjust the layout before the print preview.

+
+
function beforePrint() {
+  grid.style.width = "180mm"; // A4 width
+  grid.style.height = "unset";
+}
+
+

3. Delayed window.print

+

Grid needs approximately 300ms to recalculate and re-render itself. So you need to make sure Grid has enough time to update its state before the print preview appears.

+
function print() {
+  beforePrint();
+  setTimeout(function () {
+    window.print();
+  }, 500); // Grid needs at least 300ms  to recalculate and repaint itself.
 }
-efx-grid {
-    min-height: 500px;
+
+

4. After printing

+

Lastly, the grid's configuration needs to be restored to its initial state. For this, the window.onafterprint hook will be triggered once printing is finished.

+
window.onafterprint = function () {
+  grid.style.width = "100%";
+  grid.style.height = "500px";
 }
-html hr {
-    margin: 5px;
+
+

Using the Printing Utility

+

Unlike the native printer above, the Printing Utility has been created to help print the grid without other components. Rows and columns will not be truncated when using the utility.

+

Basically, the utility creates a new grid DOM dynamically and copies its data into this newly created grid. It will be destroyed automatically when printing is finished.

+
efx-grid {
+    height: 300px;
 }
 
-
Language:
-<select id="lang_selector">
-    <option value="en">English</option>
-    <option value="ja">Japanese</option>
-    <option value="de">German</option>
-    <option value="zh">Simplified Chinese</option>
-    <option value="zh-Hant">Traditional Chinese</option>
-</select>
-<hr>
+
<button id="print">print</button>
 <efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
@@ -42,154 +58,54 @@ 

Demo

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var columnFormattingExt = new ColumnFormatting(); -var contextMenuExt = new ContextMenu(); - -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "CF_VOLUME", "TR.IPODate"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "icon"]; +DataGenerator.addFieldInfo("icon", { + type: "set", + members: ["up", "down", "phone", "calendar", "flame"] +}); +var records = DataGenerator.generateRecords(fields, { numRows: 20 }); var configObj = { columns: [ {name: "Company", field: fields[0]}, {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80, alignment: "right"}, - {name: "Net. Chng", field: fields[3], width: 80, alignment: "right"}, - {name: "Volume", field: fields[4], alignment: "right"}, - {name: "IPO date", field: fields[5], width: 100} + {name: "Last", field: fields[2], width: 80}, + {name: "Net. Chng", field: fields[3], width: 80}, + {name: "Industry", field: fields[4]}, + {name: "Icon", field: fields[5], binding: EFIconFormatter.create()} ], - staticDataRows: records, - contextMenu: { - items: { - MENU_1: { - text: "Format", - callback: function (e) { - var lang = document.getElementById("lang_selector").value; - columnFormattingExt.openDialog(e.colIndex, { - lang: lang - }); - } - } - }, - onMenu: function (e) { - e.menu.addItem("MENU_1"); - } - }, - extensions: [ - columnFormattingExt, - contextMenuExt - ] + staticDataRows: records }; var grid = document.getElementById("grid"); grid.config = configObj; -
-
-

For more information about the extension see the Column Formatting Extension page.

-
-

Setup guide

-

First, let's import the modules.

-
// efx-grid
-import "@refinitiv-ui/efx-grid";
-import "@refinitiv-ui/efx-grid/themes/halo/light";
-
-// extensions
-import {
-    ConditionalColoring,
-    HeatMap,
-    TextFormatting,
-    ColumnFormatting
- } from "@refinitiv-ui/efx-grid/extensions";
 
-// Column Formatting Dialog module
-import "@refinitiv-ui/efx-grid/column-format-dialog";
-import "@refinitiv-ui/efx-grid/column-format-dialog/themes/halo/light";
+document.getElementById("print").addEventListener("click", function() {
+    GridPrinter.print(grid);
+  });
 
-

Create a new Column Formatting Extension instance and push it to an extensions configuration.

-
var cfe = new ColumnFormatting();
-
-var configObj = {
-    extensions: [
-        cfe,
-        new TextFormatting(),
-        new HeatMap(),
-        new ConditionalColoring()
-    ],
-    columns: columns, // Columns config
-    staticDataRows: dataRows
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
+

First, install package from npm.

+
npm install @refinitiv-ui/efx-grid
 
-

To open the dialog, you need to call openDialog() method on the extension object.

-
cfe.openDialog(0); // Change "0" to any column index.
-
-// Or open the dialog with specific configuration.
-cfe.openDialog(0, {
-    supportDisplayStyleOptions: {
-        fx: true,
-    },
-    supportValueFormatOptions: {
-        fx: true
-    }
-    supportHighlightApplyToSwitch: true,
-    data: {
-        "fieldList": [{"value": "col1"}, {"value": "col2"}, {"value": "col3"}, {"value": "col4"}, {"value": "col5"}],
-        "valueFormatTab": {"formatType": "general"},
-        "colorTextTab": {"colorText": {"field": "col2"}},
-        "displayStyleTab": {"general": {"alignment": "center"}, "mode": "general"},
-        "fieldDataType": "general"
-    },
-    fields: ["intCol", "strCol", "boolCol", "floatCol", "dateCol"],
-});
+

Then, use import syntax for importing the utility into your app.

+
import { GridPrinter } from "@refinitiv-ui/efx-grid/utils";
 
-

Changing Language

-

For more information about internationalization and how is it applied in different contexts see Language Support.

-

Using with Context Menu Extension

-

For most cases, you will want the dialog button to appear when the user right-clicks on the column header (known as the context menu).

-

To do this, simply import Context Menu extension and its configurations.

-
import {
-    ContextMenu,
-    ColumnFormatting,
-    TextFormatting,
-    HeatMap,
-    ConditionalColoring
-} from "@refinitiv-ui/efx-grid/extensions";
+

Finally, send Grid into the GridPrinter utility.

+
var config = {
+    // ... See column options for available options
+};
 
-var cfe = new ColumnFormatting();
+var grid = document.getElementById("grid");
+grid.config = config;
 
-var configObj = {
-    extensions: [
-        cfe,
-        new ContextMenu(),
-        new TextFormatting(),
-        new HeatMap(),
-        new ConditionalColoring()
-    ],
-    columns: columns, // Columns config
-    staticDataRows: dataRows,
-    contextMenu: {
-        items: {
-            MENU_1: {
-                text: "Format",
-                callback: function (e) {
-                    // Open the dialog when click on the "Format" menu
-                    cfe.openDialog(e.colIndex);
-                }
-            },
-        },
-        onMenu: function (e) {
-            e.menu.addItem("MENU_1");
-        }
-    },
-};
+GridPrinter.print(grid);
 
-

And that's it!

-

API Reference

-

ColumnFormatDialog()

Type Definitions

-
typedef

Config

Type:
Object
Properties:
Name Type Attributes Description
data Object Context object indicating current states of the column
supportHighlightApplyToSwitch boolean <optional>
support HighlightApplyToSwitch
supportValueFormatOptions ColumnFormatDialog~SupportValueFormatOptions <optional>
Support FxFormat
supportDisplayStyleOptions ColumnFormatDialog~SupportDisplayStyleOptions <optional>
Support items in "Display Style" dropdown
fields Array.<string> <optional>
List of available fields to be shown in the dialog
confirm function <optional>
Confirm event callback
cancel function <optional>
Cancel event callback
-
typedef

SupportDisplayStyleOptions

Type:
Object
Properties:
Name Type Description
bar boolean support "bar"
-
typedef

SupportValueFormatOptions

Type:
Object
Properties:
Name Type Description
fx boolean support "fx"

Methods

-
function

hide()

Hide the dialog
-
function

init(userConfigopt)

Parameters:
userConfig
<optional>
Configuration object used to initialize dialog and populate data
-
function

show()

Show the dialog
-
function

updateDataWithAutosuggest(selectedItem, autoSuggest)

Parameters:
selectedItem
Object
autosuggest selection
autoSuggest
Object
source autosuggest element
\ No newline at end of file +

GridPrinter API Reference

+

GridPrinter

Type Definitions

+
typedef

Options

Configuration object for customizing priting behavior can be passed through `GridPrinter.setPrintOptions` method
Type:
Object
Properties:
Name Type Attributes Description
pageWidth number <optional>
Paper width in pixel. This limits number of columns to be shown on a single page
pageHeight number <optional>
Paper height in pixel. This limits number of rows to be shown on a single page
primaryColumn number <optional>
Column index that will be placed as the first column on each page.

Methods

+
function

createPrintElement(grid, optionsopt) → {Element}

Parameters:
grid
*
grid element, currently supports efx-grid, emerald-grid, tr.CompositeGrid, rt.Grid and Core
options
Object
<optional>
Returns:
Element
+
function

enableDebugMode(boolopt)

Parameters:
bool
boolean
<optional>
+
function

getPreFlightInfo(grid, optionsopt) → {Object}

Parameters:
grid
tr.Grid
options
Object
<optional>
Returns:
Object
+
function

observe(iFrameElementopt)

Parameters:
iFrameElement
HTMLIFrameElement
<optional>
If not specified, current window is used instead. Specify null to un-observe existing window object.
+
function

print(grid)

Parameters:
grid
*
grid element, currently supports efx-grid, efx-grid, emerald-grid, tr.CompositeGrid, rt.Grid and Core
+
function

setPrintOptions(options)

Parameters:
options
GridPrinter.Options
+
function

unobserve()

\ No newline at end of file diff --git a/template-152.html b/template-152.html index 52a338f1..c31853eb 100644 --- a/template-152.html +++ b/template-152.html @@ -1,21 +1,25 @@ -

Column Selection Dialog

-

The Column Selection Dialog is UI for managing Grid's columns.

+

Column Format Dialog

+

The Column Format Dialog is a user-friendly interface for column display customization. It can format a column's value display from General to Number, Scaled, Percent or Datetime, and so on.

Features

    -
  • Allow users to show/hide columns and change order of the visible columns.
  • -
  • Allow users to search columns by name.
  • -
  • Allow users to add a tag and search only for columns with the specified tags.
  • +
  • Value formatting: number, scaled, date and time, and FX formats
  • +
  • Heatmap
  • +
  • Conditional coloring
  • +
  • Colored texts and background

Demo

-

Click on Open Dialog button to see the dialog.

-
html hr {
-    margin: 5px;
+

Right-click on each column header to see the dialog.

+
textarea {
+    width: 100%;
+    height: 100px;
 }
-
 efx-grid {
-    height: 500px;
+    min-height: 500px;
+}
+html hr {
+    margin: 5px;
 }
 
Language:
@@ -26,7 +30,6 @@ 

Demo

<option value="zh">Simplified Chinese</option> <option value="zh-Hant">Traditional Chinese</option> </select> -<ef-button id="open_btn">Open Dialog</ef-button> <hr> <efx-grid id="grid"></efx-grid>
@@ -39,503 +42,154 @@

Demo

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "CF_VOLUMN", "date", "PCTCHNG2"]; -var records = DataGenerator.generateRecords(fields, { numRows: 6 }); - -var allColumns = [ - {name: "Company", field: fields[0], disabled: true}, - {name: "Market", field: fields[1], width: 100}, - {name: "Last", field: fields[2], width: 80, alignment: "right"}, - {name: "Net. Chng", field: fields[3], width: 80, alignment: "right"}, - {name: "Industry", field: fields[4]}, - {name: "Volumn", field: fields[5], alignment: "right"}, - {name: "IPO Date", field: fields[6]}, - {name: "Pct. Chng", field: fields[7], alignment: "right"} -]; +var columnFormattingExt = new ColumnFormatting(); +var contextMenuExt = new ContextMenu(); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "CF_VOLUME", "TR.IPODate"]; +var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { - staticDataRows: records -}; - -var grid = document.getElementById("grid"); -grid.config = configObj; - -grid.columns = [ - allColumns[0], - allColumns[1], - allColumns[2], - allColumns[3], - allColumns[4] -]; - -var dialog = document.createElement("column-selection-dialog"); -dialog.config = { - data: allColumns, - defaultItems: grid.columns -}; -dialog.addEventListener("confirm", function (e) { - grid.columns = e.detail.value; -}); - -document.getElementById("open_btn").addEventListener("click", function () { - var lang = document.getElementById("lang_selector").value; - dialog.lang = lang; - dialog.visibleItems = grid.api.getConfigObject().columns; - dialog.show(); -}); -
-

Setup guide

-
// efx-grid
-import '@refinitiv-ui/efx-grid';
-import '@refinitiv-ui/efx-grid/themes/halo/light';
-
-// Column Selection Dialog module
-import '@refinitiv-ui/efx-grid/column-selection-dialog';
-import '@refinitiv-ui/efx-grid/column-selection-dialog/themes/halo/light';
-
-

Create a column-selection-dialog using the document.createElement method. This way, the column-selection-dialog DOM instance will not be mounted initially.

-
var dialog = document.createElement("column-selection-dialog");
-
-

Then you need to subscribe to confirm event which will be fired when the user has confirmed their changes. It is also required to directly manipulate grid.columns with the e.detail.value like below.

-
dialog.addEventListener("confirm", function (e) {
-    var grid = document.getElementById("grid");
-    grid.columns = e.detail.value;
-});
-
-

By default, once users click Done the dialog will automatically hide. In order to prevent the dialog from closing (eg. Validate something before closing), use beforeConfirm event and set e.cancel to true.

-
dialog.addEventListener("beforeConfirm", function (e) {
-    if (/*Some logic*/) {
-        e.cancel = true;
-        window.alert("Don't hide the dialog");
-    }
-});
-
-

Then set initial data using the init(configObj) method. This takes a configuration object consisting of two properties, data and visibleItems. Alternatively, the same configuration can be set through config property. For example, dialog.config = configObj;

-
var columns = [/* Grid Column Option */];
-var grid = document.getElementsByTagName("efx-grid")[0];
-grid.config = {/* Grid Option */};
-grid.columns = columns; // Explicitly set columns, otherwise it will be undefined
-
-dialog.config = {
-    data: columns, // All columns
-    visibleItems: grid.columns // Currently visible columns
-};
-
-
-

Note: grid.columns needs to be set explicitly due to limitations of the Grid.

-
-

Finally, to open the dialog you need to call dialog.show() method on dialog element.

-
dialog.show();
-
-

Changing Language

-

For more information about internationalization and how is it applied in different contexts see Language Support.

-

Multi Level with Column Selection

-
html hr {
-    margin: 5px;
-}
-efx-grid {
-    height: 500px;
-}
-
-
<button id="open_btn">Open Dialog</button>
-<hr>
-<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "CF_VOLUMN", "date", "PCTCHNG2"];
-    var records = DataGenerator.generateRecords(fields, 20);
-
-    var allColumns = [
-        {name: "Company", field: fields[0], disabled: true},
+    columns: [
+        {name: "Company", field: fields[0]},
         {name: "Market", field: fields[1], width: 100},
         {name: "Last", field: fields[2], width: 80, alignment: "right"},
         {name: "Net. Chng", field: fields[3], width: 80, alignment: "right"},
-        {name: "Industry", field: fields[4]},
-        {name: "Volumn", field: fields[5], alignment: "right"},
-        {name: "IPO Date", field: fields[6]},
-        {name: "Pct. Chng", field: fields[7], alignment: "right"}
-    ];
-
-    var configObj = {
-        staticDataRows: records
-    };
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-grid.columns = [
-    allColumns[0],
-    allColumns[1],
-    allColumns[2],
-    allColumns[3],
-    allColumns[4]
-];
-
-var columnTree = [
-    allColumns[0],
-    {
-        label: 'Basic Info',
-        items: [
-            allColumns[1],
-            allColumns[4],
-            allColumns[6]
-        ]
-    },
-    {
-        label: 'Trading Info',
-        items: [
-            {
-                label: 'Net.',
-                items: [
-                    allColumns[2],
-                    allColumns[3],
-                    allColumns[5]
-                ]
-            },
-            {
-                label: 'Percent',
-                items: [
-                    allColumns[7]
-                ]
+        {name: "Volume", field: fields[4], alignment: "right"},
+        {name: "IPO date", field: fields[5], width: 100}
+    ],
+    staticDataRows: records,
+    contextMenu: {
+        items: {
+            MENU_1: {
+                text: "Format",
+                callback: function (e) {
+                    var lang = document.getElementById("lang_selector").value;
+                    columnFormattingExt.openDialog(e.colIndex, {
+                        lang: lang
+                    });
+                }
             }
-        ]
-    }
-];
-
-var dialog = document.createElement("column-selection-dialog");
-dialog.config = {
-    data: columnTree
-};
-
-dialog.addEventListener("confirm", function (e) {
-        grid.columns = e.detail.value;
-});
-
-document.getElementById("open_btn").addEventListener("click", function () {
-    dialog.visibleItems = grid.api.getConfigObject().columns;
-    dialog.show();
-});
-
-

Disabled column

-

In case you do not want specific columns to move out of the grid, you can set the flag as disabled for that specific column, as the example below:

-
var columns = [/* Grid Column Option */];
-var grid = document.getElementById("grid_id");
-grid.config = {/* Grid Option */};
-grid.columns = columns; // Explicitly set columns, otherwise it will be undefined
-
-columns[1].disabled = true; // To prevent this column from moving between the lists
-dialog.config = {
-    data: columns, // All columns
-    visibleItems: columns// Currently visible columns
+        },
+        onMenu: function (e) {
+            e.menu.addItem("MENU_1");
+        }
+    },
+    extensions: [
+        columnFormattingExt,
+        contextMenuExt
+    ]
 };
-
-

Stationary column

-

In case you are having pinned columns, and you do not want pinned columns to be moved or removed from the grid, you can enable the stationary flag to disable select and moving operation for that specific column.

-
html hr {
-    margin: 5px;
-}
-
-
<button id="open_btn">Open Dialog</button>
-<hr>
-<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "CF_VOLUMN", "date", "PCTCHNG2"];
-    var records = DataGenerator.generateRecords(fields, 20);
-
-    var allColumns = [
-        {name: "Company", field: fields[0], width: 250, leftPinned: true, stationary: true},
-        {name: "Market", field: fields[1], width: 250},
-        {name: "Last", field: fields[2], width: 120, alignment: "right"},
-        {name: "Net. Chng", field: fields[3], width: 100, alignment: "right"},
-        {name: "Industry", field: fields[4], width: 200},
-        {name: "Volumn", field: fields[5], width: 100, alignment: "right"},
-        {name: "IPO Date", field: fields[6], width: 100},
-        {name: "Pct. Chng", field: fields[7], width: 100, alignment: "right"}
-    ];
-
-    var configObj = {
-        staticDataRows: records
-    };
 
 var grid = document.getElementById("grid");
 grid.config = configObj;
-
-grid.columns = [
-    allColumns[0],
-    allColumns[1],
-    allColumns[2],
-    allColumns[3],
-    allColumns[4]
-];
-
-var columnTree = [
-    allColumns[0],
-    {
-        label: 'Basic Info',
-        items: [
-            allColumns[1],
-            allColumns[4],
-            allColumns[6]
-        ]
-    },
-    {
-        label: 'Trading Info',
-        items: [
-            {
-                label: 'Net.',
-                items: [
-                    allColumns[2],
-                    allColumns[3],
-                    allColumns[5]
-                ]
-            },
-            {
-                label: 'Percent',
-                items: [
-                    allColumns[7]
-                ]
-            }
-        ]
-    }
-];
-
-var dialog = document.createElement("column-selection-dialog");
-dialog.config = {
-    data: columnTree
-};
-
-dialog.addEventListener("confirm", function (e) {
-        grid.columns = e.detail.value;
-});
-
-document.getElementById("open_btn").addEventListener("click", function () {
-    dialog.visibleItems = grid.api.getConfigObject().columns;
-    dialog.show();
-});
 
-

Note:

-
    -
  • Disabled column will only prevent column from selection and deselection, but the column is still movable.
  • -
  • Stationary column will not allow the column to be deselected or changing its order.
  • -
+

For more information about the extension see the Column Formatting Extension page.

-

Hide Columns in Visible Columns

-

There is a use case where you might not want some columns to be moved. You can disable the number of columns in the visible columns using excludedColumns config.

-
dialog.config = {
-    // Other dialog config
-    excludedColumns: 2, // This will make column index 0-1 hidden in the Visible Columns.
-};
-
-

Default Columns

-

The "RESTORE DEFAULT" button will show only when defaultItems has been set. This button will reset all visible columns to default.

-
var allColumns = [
-    {name: "Company", field: fields[0], disabled: true},
-    {name: "Market", field: fields[1], width: 100},
-    {name: "Last", field: fields[2], width: 80, alignment: "right"},
-    {name: "Net. Chng", field: fields[3], width: 80, alignment: "right"},
-    {name: "Industry", field: fields[4]},
-    {name: "Volumn", field: fields[5], alignment: "right"},
-    {name: "IPO Date", field: fields[6]},
-    {name: "Pct. Chng", field: fields[7], alignment: "right"}
-];
-
-grid.columns = [
-    allColumns[0],
-    allColumns[1],
-    allColumns[2],
-    allColumns[3],
-    allColumns[4]
-];
-
-dialog.config = {
-    // Other dialog config
-    defaultItems: grid.columns
-};
-
-
-

Note: availableItems is deprecated.

-
-

Restoring columns with retaining sorting and filtering states

-

The Column Selection Dialog only provides column information to the user. If you wish to retain certain states, such as sorting and filtering, you will need to utilize the grid API to restore the updated data back to the grid from your side.

-

In the example below, we will demonstrate how to retain the sorting and filtering state in the grid when confirming the column selection dialog.

-
html hr {
-    margin: 5px;
-}
-efx-grid {
-    height: 500px;
-}
-
-
<button id="open_btn">Open Dialog</button>
-<hr>
-<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var rowFilteringExt = new RowFiltering();
-
-    var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "CF_VOLUMN", "date", "PCTCHNG2"];
-    var records = DataGenerator.generateRecords(fields, 20);
-    var allColumns = [
-        {name: "Company", field: fields[0], disabled: true},
-        {name: "Market", field: fields[1], width: 100},
-        {name: "Last", field: fields[2], width: 80, alignment: "right"},
-        {name: "Net. Chng", field: fields[3], width: 80, alignment: "right"},
-        {name: "Industry", field: fields[4]},
-        {name: "Volumn", field: fields[5], alignment: "right"},
-        {name: "IPO Date", field: fields[6]},
-        {name: "Pct. Chng", field: fields[7], alignment: "right"}
-    ];
-
-    var configObj = {
-        staticDataRows: records,
-        extensions: [rowFilteringExt],
-        rowFiltering: {
-            iconActivation: "always"
-        },
-    };
-
-    var grid = document.getElementById("grid");
-    grid.config = configObj;
-
-    grid.columns = [
-        allColumns[0],
-        allColumns[1],
-        allColumns[2],
-        allColumns[3],
-        allColumns[4]
-    ];
-
-    var dialog = document.createElement("column-selection-dialog");
-    dialog.config = {
-        data: allColumns,
-        defaultItems: grid.columns
-    };
+

Setup guide

+

First, let's import the modules.

+
// efx-grid
+import "@refinitiv-ui/efx-grid";
+import "@refinitiv-ui/efx-grid/themes/halo/light";
 
-    dialog.addEventListener("confirm", function (e) {
-        grid.api.restoreColumns(e.detail.data, true);
-    });
+// extensions
+import {
+    ConditionalColoring,
+    HeatMap,
+    TextFormatting,
+    ColumnFormatting
+ } from "@refinitiv-ui/efx-grid/extensions";
 
-    document.getElementById("open_btn").addEventListener("click", function () {
-        dialog.visibleItems = grid.api.getConfigObject().columns;
-        dialog.show();
-    });
+// Column Formatting Dialog module
+import "@refinitiv-ui/efx-grid/column-format-dialog";
+import "@refinitiv-ui/efx-grid/column-format-dialog/themes/halo/light";
 
-

Tag searching

-

To add available tag list to the dialog, set an array of tags to tags property on the dialog configuration object. tags property can also be set on column configuration object for matching.

-
html hr {
-    margin: 5px;
-}
-efx-grid {
-    height: 500px;
-}
-
-
<button id="open_btn">Open Dialog</button>
-<hr>
-<big id="msg_big"></big>
-<hr>
-<efx-grid id="grid"></efx-grid>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var availableTags = ["Runner", "Swimmer", "Flier", "red", "green", "blue"];
-var fieldDefs = [
-    ["Red Dog", ["red", "runner", "running"]],
-    ["Red Snake", ["red"]],
-    ["Blue Penguin", ["Blue", "Runner", "Running", "Swimmer"]],
-    ["Blue Bird", ["Blue", "Flier"]],
-    ["Blue Chicken", ["Blue", "runner", "running"]],
-    ["Green Lion", ["Green", "Runner", "running"]],
-    ["Red Bat", ["red", "Flier"]],
-    ["Green Frog", ["Green", "Swimmer"]],
-    ["Blue Rabbit", ["Blue", "Runner", "running"]],
-    ["Red Fish", ["red", "Swimmer"]]
-];
-document.getElementById("msg_big").textContent = "Available tags: " + availableTags.join(", ");
-var columnDefMap = fieldDefs.reduce(function(obj, def) { 
-    var field = def[0];
-    var tag = def[1];
-    obj[field] = {
-        field: field,
-        id: field,
-        tags: tag
-    };
-    return obj;
-}, {});
-function idToColumnDef(colId) {
-    return columnDefMap[colId] || null;
-}
-
-var fields = Object.keys(columnDefMap);
-var availableColumns = Object.values(columnDefMap);
+

Create a new Column Formatting Extension instance and push it to an extensions configuration.

+
var cfe = new ColumnFormatting();
 
-var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 });
 var configObj = {
-    staticDataRows: records
+    extensions: [
+        cfe,
+        new TextFormatting(),
+        new HeatMap(),
+        new ConditionalColoring()
+    ],
+    columns: columns, // Columns config
+    staticDataRows: dataRows
 };
 
 var grid = document.getElementById("grid");
 grid.config = configObj;
-grid.columns = availableColumns.slice(0, 4);
-
-function onConfirm(e) {
-    grid.columns = e.detail.value;
-}
-
-var dialog = null;
-document.getElementById("open_btn").addEventListener("click", function () {
-    if (!dialog) {
-        dialog = document.createElement("column-selection-dialog");
+
+

To open the dialog, you need to call openDialog() method on the extension object.

+
cfe.openDialog(0); // Change "0" to any column index.
 
-        dialog.config = {
-            data: availableColumns,
-            confirm: onConfirm,
-            tags: availableTags,
-            infoTooltip: "Search Column to add to the right list. Press Tab to add a Tag. Available tags for Search: Red, Blue, Green, Runner, Swimmer, and Flier",
-            searchPlaceholder: "Search Column. Press Tab to add a Tag"
-        };
+// Or open the dialog with specific configuration.
+cfe.openDialog(0, {
+    supportDisplayStyleOptions: {
+        fx: true,
+    },
+    supportValueFormatOptions: {
+        fx: true
     }
-    
-    var columnIds = grid.api.getColumnIds();
-    dialog.visibleItems = columnIds.map(idToColumnDef);
-    
-    dialog.show();
+    supportHighlightApplyToSwitch: true,
+    data: {
+        "fieldList": [{"value": "col1"}, {"value": "col2"}, {"value": "col3"}, {"value": "col4"}, {"value": "col5"}],
+        "valueFormatTab": {"formatType": "general"},
+        "colorTextTab": {"colorText": {"field": "col2"}},
+        "displayStyleTab": {"general": {"alignment": "center"}, "mode": "general"},
+        "fieldDataType": "general"
+    },
+    fields: ["intCol", "strCol", "boolCol", "floatCol", "dateCol"],
 });
 
-

API Reference

-

ColumnSelectionDialog()

Type Definitions

-
typedef

Config

Type:
Object
Properties:
Name Type Attributes Default Description
data Array.<Object> All possible columns for selection.
visibleItems Array.<Object> <optional>
Column list that is in existing Grid.
defaultItems Array.<Object> <optional>
Column list that is default.
confirm function <optional>
Confirm event callback.
cancel function <optional>
Cancel event callback.
excludedColumns number <optional>
Deprecated, Alias wigh excludedLeftColumns.
excludedLeftColumns number <optional>
Number of columns on the left side that should be hidden from Visible Columns.
excludedRightColumns number <optional>
Number of columns on the right side that should be hidden from Visible Columns.
unmovableColumns number <optional>
Depricated, Alias with stationary column option. Number of columns that is unmovable in Visible Columns.
descriptionBox boolean <optional>
Show description box
middleSeparator string <optional>
Field of column which used as middle separator to divide grid into two sides
collapseAll boolean <optional>
false Default collapse property applies to all groups
width number <optional>
Specify width of the dialog, with the minimum width of 490px
height number <optional>
Specify height of the dialog
tags Array.<string> <optional>
null All available tags for filtering
infoTooltip string <optional>
"" If specified, an informational icon will appear on the top with the given text as its tooltip
searchPlaceholder string <optional>
"Search" Placeholder text inside the search input.

Methods

+

Changing Language

+

For more information about internationalization and how is it applied in different contexts see Language Support.

+

Using with Context Menu Extension

+

For most cases, you will want the dialog button to appear when the user right-clicks on the column header (known as the context menu).

+

To do this, simply import Context Menu extension and its configurations.

+
import {
+    ContextMenu,
+    ColumnFormatting,
+    TextFormatting,
+    HeatMap,
+    ConditionalColoring
+} from "@refinitiv-ui/efx-grid/extensions";
+
+var cfe = new ColumnFormatting();
+
+var configObj = {
+    extensions: [
+        cfe,
+        new ContextMenu(),
+        new TextFormatting(),
+        new HeatMap(),
+        new ConditionalColoring()
+    ],
+    columns: columns, // Columns config
+    staticDataRows: dataRows,
+    contextMenu: {
+        items: {
+            MENU_1: {
+                text: "Format",
+                callback: function (e) {
+                    // Open the dialog when click on the "Format" menu
+                    cfe.openDialog(e.colIndex);
+                }
+            },
+        },
+        onMenu: function (e) {
+            e.menu.addItem("MENU_1");
+        }
+    },
+};
+
+

And that's it!

+

API Reference

+

ColumnFormatDialog()

Type Definitions

+
typedef

Config

Type:
Object
Properties:
Name Type Attributes Description
data Object Context object indicating current states of the column
supportHighlightApplyToSwitch boolean <optional>
support HighlightApplyToSwitch
supportValueFormatOptions ColumnFormatDialog~SupportValueFormatOptions <optional>
Support FxFormat
supportDisplayStyleOptions ColumnFormatDialog~SupportDisplayStyleOptions <optional>
Support items in "Display Style" dropdown
fields Array.<string> <optional>
List of available fields to be shown in the dialog
confirm function <optional>
Confirm event callback
cancel function <optional>
Cancel event callback
+
typedef

SupportDisplayStyleOptions

Type:
Object
Properties:
Name Type Description
bar boolean support "bar"
+
typedef

SupportValueFormatOptions

Type:
Object
Properties:
Name Type Description
fx boolean support "fx"

Methods

function

hide()

Hide the dialog
-
function

init(optionsopt)

Parameters:
options
<optional>
-
function

show()

Show the dialog
\ No newline at end of file +
function

init(userConfigopt)

Parameters:
userConfig
<optional>
Configuration object used to initialize dialog and populate data
+
function

show()

Show the dialog
+
function

updateDataWithAutosuggest(selectedItem, autoSuggest)

Parameters:
selectedItem
Object
autosuggest selection
autoSuggest
Object
source autosuggest element
\ No newline at end of file diff --git a/template-153.html b/template-153.html index 249b2d64..52a338f1 100644 --- a/template-153.html +++ b/template-153.html @@ -1,15 +1,34 @@ -

Filter Dialog

-

The Filter Dialog is a user-friendly interface for filtering and sorting. The example below shows how Filter Dialog can be used in conjunction with Row Filtering Extension. Users can hover over column header to show filter icon. Clicking on the icon will open Filter Dialog.

-
body {
-    padding: 2px;
+

Column Selection Dialog

+

The Column Selection Dialog is UI for managing Grid's columns.

+

Features

+
    +
  • Allow users to show/hide columns and change order of the visible columns.
  • +
  • Allow users to search columns by name.
  • +
  • Allow users to add a tag and search only for columns with the specified tags.
  • +
+

Demo

+

Click on Open Dialog button to see the dialog.

+
html hr {
+    margin: 5px;
 }
+
 efx-grid {
     height: 500px;
 }
 
-
<efx-grid id="grid"></efx-grid>
+
Language:
+<select id="lang_selector">
+    <option value="en">English</option>
+    <option value="ja">Japanese</option>
+    <option value="de">German</option>
+    <option value="zh">Simplified Chinese</option>
+    <option value="zh-Hant">Traditional Chinese</option>
+</select>
+<ef-button id="open_btn">Open Dialog</ef-button>
+<hr>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -20,68 +39,107 @@ 

Filter Dialog

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 }); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "CF_VOLUMN", "date", "PCTCHNG2"]; +var records = DataGenerator.generateRecords(fields, { numRows: 6 }); + +var allColumns = [ + {name: "Company", field: fields[0], disabled: true}, + {name: "Market", field: fields[1], width: 100}, + {name: "Last", field: fields[2], width: 80, alignment: "right"}, + {name: "Net. Chng", field: fields[3], width: 80, alignment: "right"}, + {name: "Industry", field: fields[4]}, + {name: "Volumn", field: fields[5], alignment: "right"}, + {name: "IPO Date", field: fields[6]}, + {name: "Pct. Chng", field: fields[7], alignment: "right"} +]; + var configObj = { - columns: [ - { name: "Company", field: fields[0] }, - { name: "Market", field: fields[1], width: 120 }, - { name: "Last", field: fields[2], width: 100 }, - { name: "Net. Chng", field: fields[3], width: 100 }, - { name: "Industry", field: fields[4] } - ], - staticDataRows: records, - rowFiltering:{ - iconActivation: "onHover" - }, - extensions: [ - new RowFiltering() - ] + staticDataRows: records }; var grid = document.getElementById("grid"); grid.config = configObj; + +grid.columns = [ + allColumns[0], + allColumns[1], + allColumns[2], + allColumns[3], + allColumns[4] +]; + +var dialog = document.createElement("column-selection-dialog"); +dialog.config = { + data: allColumns, + defaultItems: grid.columns +}; +dialog.addEventListener("confirm", function (e) { + grid.columns = e.detail.value; +}); + +document.getElementById("open_btn").addEventListener("click", function () { + var lang = document.getElementById("lang_selector").value; + dialog.lang = lang; + dialog.visibleItems = grid.api.getConfigObject().columns; + dialog.show(); +});

Setup guide

-
 // efx-grid
-import "@refinitiv-ui/efx-grid";
-import "@refinitiv-ui/efx-grid/themes/halo/light";
-
-// Extensions
-import { RowFiltering } from "@refinitiv-ui/efx-grid/extensions";
+
// efx-grid
+import '@refinitiv-ui/efx-grid';
+import '@refinitiv-ui/efx-grid/themes/halo/light';
 
-// Filter Dialog module
-import "@refinitiv-ui/efx-grid/filter-dialog";
-import "@refinitiv-ui/efx-grid/filter-dialog/themes/halo/light";  // !Important. Theme must be imported.
+// Column Selection Dialog module
+import '@refinitiv-ui/efx-grid/column-selection-dialog';
+import '@refinitiv-ui/efx-grid/column-selection-dialog/themes/halo/light';
+
+

Create a column-selection-dialog using the document.createElement method. This way, the column-selection-dialog DOM instance will not be mounted initially.

+
var dialog = document.createElement("column-selection-dialog");
+
+

Then you need to subscribe to confirm event which will be fired when the user has confirmed their changes. It is also required to directly manipulate grid.columns with the e.detail.value like below.

+
dialog.addEventListener("confirm", function (e) {
+    var grid = document.getElementById("grid");
+    grid.columns = e.detail.value;
+});
 
-

The dialog cannot be used without Row Filtering Extension. So, initialize Row Filtering Extension instance and add it to extensions property on the grid configuration object. To open the dialog, you can either use iconActivation property or openDialog method from the extension.

-
var rowFilteringExt = new RowFiltering();
+

By default, once users click Done the dialog will automatically hide. In order to prevent the dialog from closing (eg. Validate something before closing), use beforeConfirm event and set e.cancel to true.

+
dialog.addEventListener("beforeConfirm", function (e) {
+    if (/*Some logic*/) {
+        e.cancel = true;
+        window.alert("Don't hide the dialog");
+    }
+});
+
+

Then set initial data using the init(configObj) method. This takes a configuration object consisting of two properties, data and visibleItems. Alternatively, the same configuration can be set through config property. For example, dialog.config = configObj;

+
var columns = [/* Grid Column Option */];
+var grid = document.getElementsByTagName("efx-grid")[0];
+grid.config = {/* Grid Option */};
+grid.columns = columns; // Explicitly set columns, otherwise it will be undefined
 
-var configObj = {
-    extensions: [
-        rowFilteringExt
-    ],
-    rowFiltering:{
-        iconActivation: "onHover"
-    },
-    columns: columns, // Columns config
-    staticDataRows: records
+dialog.config = {
+    data: columns, // All columns
+    visibleItems: grid.columns // Currently visible columns
 };
-
-var grid = document.getElementById("grid_id");
-grid.config = configObj;
-
-function onClickButton(e) {
-  rowFilteringExt.openDialog(columnIndex);
-}
 
-

Advanced condition tab

-

Filter dialog has three types of condition tabs: generic value condition (default), numeric value condition, and date time value condition. Each type has a different list of available operators. For example, numeric value condition contains only nemeric operators, such as Less than or Greater than operators. To specify the type for the dialog, define fieldDataType property on the column configuration object to one of the following values: number, datetime, and text or nothing (default).

-
efx-grid {
+
+

Note: grid.columns needs to be set explicitly due to limitations of the Grid.

+
+

Finally, to open the dialog you need to call dialog.show() method on dialog element.

+
dialog.show();
+
+

Changing Language

+

For more information about internationalization and how is it applied in different contexts see Language Support.

+

Multi Level with Column Selection

+
html hr {
+    margin: 5px;
+}
+efx-grid {
     height: 500px;
 }
 
-
<efx-grid id="grid"></efx-grid>
+
<button id="open_btn">Open Dialog</button>
+<hr>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -92,66 +150,102 @@ 

Advanced condition tab

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "CF_NETCHNG", "ISODate"]; -var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 }); -var configObj = { - columns: [ - { name: "Company", field: "companyName" }, - { name: "Company (text)", field: "companyName", fieldDataType: "text" }, - { name: "Date (generic)", field: "ISODate", width: 180 }, - { name: "Date (datetime)", field: "ISODate", width: 180, fieldDataType: "datetime" }, - { name: "Change (generic)", field: "CF_NETCHNG", width: 130 }, - { name: "Change (number)", field: "CF_NETCHNG", width: 130, fieldDataType: "number" } - ], - staticDataRows: records, - rowFiltering:{ - iconActivation: "onHover" - }, - extensions: [ - new RowFiltering() - ] -}; +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "CF_VOLUMN", "date", "PCTCHNG2"]; + var records = DataGenerator.generateRecords(fields, 20); + + var allColumns = [ + {name: "Company", field: fields[0], disabled: true}, + {name: "Market", field: fields[1], width: 100}, + {name: "Last", field: fields[2], width: 80, alignment: "right"}, + {name: "Net. Chng", field: fields[3], width: 80, alignment: "right"}, + {name: "Industry", field: fields[4]}, + {name: "Volumn", field: fields[5], alignment: "right"}, + {name: "IPO Date", field: fields[6]}, + {name: "Pct. Chng", field: fields[7], alignment: "right"} + ]; + + var configObj = { + staticDataRows: records + }; var grid = document.getElementById("grid"); grid.config = configObj; -
-

Dialog options

-

Filter Dialog can be customized by setting dialogOptions property on the Row Filtering Extension configuration object as shown in the following code snippet:

-
var configObj = {
-    rowFiltering: {
-        dialogOptions: {
-            sortUI: false
-        }
+
+grid.columns = [
+    allColumns[0],
+    allColumns[1],
+    allColumns[2],
+    allColumns[3],
+    allColumns[4]
+];
+
+var columnTree = [
+    allColumns[0],
+    {
+        label: 'Basic Info',
+        items: [
+            allColumns[1],
+            allColumns[4],
+            allColumns[6]
+        ]
+    },
+    {
+        label: 'Trading Info',
+        items: [
+            {
+                label: 'Net.',
+                items: [
+                    allColumns[2],
+                    allColumns[3],
+                    allColumns[5]
+                ]
+            },
+            {
+                label: 'Percent',
+                items: [
+                    allColumns[7]
+                ]
+            }
+        ]
     }
+];
+
+var dialog = document.createElement("column-selection-dialog");
+dialog.config = {
+    data: columnTree
 };
+
+dialog.addEventListener("confirm", function (e) {
+        grid.columns = e.detail.value;
+});
+
+document.getElementById("open_btn").addEventListener("click", function () {
+    dialog.visibleItems = grid.api.getConfigObject().columns;
+    dialog.show();
+});
 
-

The options will be applied for every column in the grid. The options can be overriden on a column basis by using beforeDialogOpened event. You can specify dialogOptions property on the event argument and override the options set on the grid level as shown in the following code snippet:

-
var configObj = {
-    rowFiltering: {
-        dialogOptions: {
-            sortUI: false
-        },
-        beforeDialogOpened: function(e) {
-            if(e.field === "field A") {
-                e.dialogOptions = {
-                    sortUI: true
-                };
-            }
-        }
-    }
+

Disabled column

+

In case you do not want specific columns to move out of the grid, you can set the flag as disabled for that specific column, as the example below:

+
var columns = [/* Grid Column Option */];
+var grid = document.getElementById("grid_id");
+grid.config = {/* Grid Option */};
+grid.columns = columns; // Explicitly set columns, otherwise it will be undefined
+
+columns[1].disabled = true; // To prevent this column from moving between the lists
+dialog.config = {
+    data: columns, // All columns
+    visibleItems: columns// Currently visible columns
 };
 
-

Customizing filter item list

-

By default, the item list in Filter Dialog is generated from existing data on the column, where the dialog is openned. Any duplicate value is automatically removed from the list. If there is formatting applied by Text Formatting Extension on the column, the items will also be formatted.

-

itemList property on the dialog options can be used to replace the autogenerated one. This is useful when you want to prevent some values from being available for filtering.

-

additionalItems property on the dialog options can be used to add more values to the existing list. The property can be used to include some nonexistent values (e.g., you have some server side filtering).

-

formattedDataAccessor property on the dialog options allows you to specify a method for transforming and displaying items on the list. The method will be called on each item and it should return the formatted text you want to display in the dialog. The method can also be used to retrieve data from an object (i.e., data with non-premitive data type).

-

sortLogic property on the dialog options allows you to specify a method for reordering items on the list. The method will be used by Array.sort method

-
efx-grid {
-    height: 300px;
+

Stationary column

+

In case you are having pinned columns, and you do not want pinned columns to be moved or removed from the grid, you can enable the stationary flag to disable select and moving operation for that specific column.

+
html hr {
+    margin: 5px;
 }
 
-
<efx-grid id="grid"></efx-grid>
+
<button id="open_btn">Open Dialog</button>
+<hr>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -162,84 +256,134 @@ 

Customizing filter item list

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var sortIdInDescendingOrder = function(valA, valB) { - if(valA < valB) { - return 1; - } - if(valB < valA) { - return -1; - } - return 0; -}; -var booleanToYesNo = function(val) { - if(val != null) { - return val ? "Yes" : "No"; - } - return ""; -}; -var onBeforeDialogOpened = function(e) { - var colIndex = e.colIndex; - if(colIndex === 0) { // id - e.dialogOptions = { - sortLogic: sortIdInDescendingOrder - }; - } else if(colIndex === 2) { // replacement - e.dialogOptions = { - itemList: ["Left", "Center", "Right"] - }; - } else if(colIndex === 3) { // addition - e.dialogOptions = { - additionalItems: [1, 0, "N/A"] - }; - } else if(colIndex === 4) { // formatted - e.dialogOptions = { - formattedDataAccessor: booleanToYesNo - }; +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "CF_VOLUMN", "date", "PCTCHNG2"]; + var records = DataGenerator.generateRecords(fields, 20); + + var allColumns = [ + {name: "Company", field: fields[0], width: 250, leftPinned: true, stationary: true}, + {name: "Market", field: fields[1], width: 250}, + {name: "Last", field: fields[2], width: 120, alignment: "right"}, + {name: "Net. Chng", field: fields[3], width: 100, alignment: "right"}, + {name: "Industry", field: fields[4], width: 200}, + {name: "Volumn", field: fields[5], width: 100, alignment: "right"}, + {name: "IPO Date", field: fields[6], width: 100}, + {name: "Pct. Chng", field: fields[7], width: 100, alignment: "right"} + ]; + + var configObj = { + staticDataRows: records + }; + +var grid = document.getElementById("grid"); +grid.config = configObj; + +grid.columns = [ + allColumns[0], + allColumns[1], + allColumns[2], + allColumns[3], + allColumns[4] +]; + +var columnTree = [ + allColumns[0], + { + label: 'Basic Info', + items: [ + allColumns[1], + allColumns[4], + allColumns[6] + ] + }, + { + label: 'Trading Info', + items: [ + { + label: 'Net.', + items: [ + allColumns[2], + allColumns[3], + allColumns[5] + ] + }, + { + label: 'Percent', + items: [ + allColumns[7] + ] + } + ] } +]; + +var dialog = document.createElement("column-selection-dialog"); +dialog.config = { + data: columnTree }; -var fields = ["id", "boolean"]; -var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 10 }); -var configObj = { - rowFiltering: { - iconActivation: "onHover", - beforeDialogOpened: onBeforeDialogOpened - }, - columns: [ - { name: "Id", field: "id", width: 80 }, - { name: "Boolean (default)", field: "boolean"}, - { name: "Boolean (replacement)", field: "boolean"}, - { name: "Boolean (addition)", field: "boolean"}, - { name: "Boolean (formatted)", field: "boolean"} - ], - staticDataRows: records, - extensions: [ - new RowFiltering() - ] + +dialog.addEventListener("confirm", function (e) { + grid.columns = e.detail.value; +}); + +document.getElementById("open_btn").addEventListener("click", function () { + dialog.visibleItems = grid.api.getConfigObject().columns; + dialog.show(); +}); +
+
+

Note:

+
    +
  • Disabled column will only prevent column from selection and deselection, but the column is still movable.
  • +
  • Stationary column will not allow the column to be deselected or changing its order.
  • +
+
+

Hide Columns in Visible Columns

+

There is a use case where you might not want some columns to be moved. You can disable the number of columns in the visible columns using excludedColumns config.

+
dialog.config = {
+    // Other dialog config
+    excludedColumns: 2, // This will make column index 0-1 hidden in the Visible Columns.
 };
+
+

Default Columns

+

The "RESTORE DEFAULT" button will show only when defaultItems has been set. This button will reset all visible columns to default.

+
var allColumns = [
+    {name: "Company", field: fields[0], disabled: true},
+    {name: "Market", field: fields[1], width: 100},
+    {name: "Last", field: fields[2], width: 80, alignment: "right"},
+    {name: "Net. Chng", field: fields[3], width: 80, alignment: "right"},
+    {name: "Industry", field: fields[4]},
+    {name: "Volumn", field: fields[5], alignment: "right"},
+    {name: "IPO Date", field: fields[6]},
+    {name: "Pct. Chng", field: fields[7], alignment: "right"}
+];
 
-var grid = document.getElementById("grid");
-grid.config = configObj;
+grid.columns = [
+    allColumns[0],
+    allColumns[1],
+    allColumns[2],
+    allColumns[3],
+    allColumns[4]
+];
+
+dialog.config = {
+    // Other dialog config
+    defaultItems: grid.columns
+};
 
-

Changing dialog language

-

For more information about internationalization and how is it applied in different contexts see Language Support.

-

Opening Filter Dialog using an API

-

The dialog can be openned from anywhere, not just from filter icon on the column header. Use openDialog method from Row Filtering extension instance, so that the dialog can be openned for specific column and linked up with grid instance.

-

The following example illustrates how the dialog can be opened from context menu using Context Menu Extension. Right click on the column header to see the dialog.

-
html hr {
+
+

Note: availableItems is deprecated.

+
+

Restoring columns with retaining sorting and filtering states

+

The Column Selection Dialog only provides column information to the user. If you wish to retain certain states, such as sorting and filtering, you will need to utilize the grid API to restore the updated data back to the grid from your side.

+

In the example below, we will demonstrate how to retain the sorting and filtering state in the grid when confirming the column selection dialog.

+
html hr {
     margin: 5px;
 }
 efx-grid {
     height: 500px;
 }
 
-
Language:
-<select id="lang_selector">
-    <option value="en">English</option>
-    <option value="ja">Japanese</option>
-    <option value="de">German</option>
-    <option value="zh">Simplified Chinese</option>
-    <option value="zh-Hant">Traditional Chinese</option>
-</select>
+
<button id="open_btn">Open Dialog</button>
 <hr>
 <efx-grid id="grid"></efx-grid>
 
@@ -253,74 +397,145 @@

Opening Filter Dialog using an API

+

Tag searching

+

To add available tag list to the dialog, set an array of tags to tags property on the dialog configuration object. tags property can also be set on column configuration object for matching.

+
html hr {
+    margin: 5px;
+}
+efx-grid {
+    height: 500px;
+}
+
+
<button id="open_btn">Open Dialog</button>
+<hr>
+<big id="msg_big"></big>
+<hr>
+<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var availableTags = ["Runner", "Swimmer", "Flier", "red", "green", "blue"];
+var fieldDefs = [
+    ["Red Dog", ["red", "runner", "running"]],
+    ["Red Snake", ["red"]],
+    ["Blue Penguin", ["Blue", "Runner", "Running", "Swimmer"]],
+    ["Blue Bird", ["Blue", "Flier"]],
+    ["Blue Chicken", ["Blue", "runner", "running"]],
+    ["Green Lion", ["Green", "Runner", "running"]],
+    ["Red Bat", ["red", "Flier"]],
+    ["Green Frog", ["Green", "Swimmer"]],
+    ["Blue Rabbit", ["Blue", "Runner", "running"]],
+    ["Red Fish", ["red", "Swimmer"]]
+];
+document.getElementById("msg_big").textContent = "Available tags: " + availableTags.join(", ");
+var columnDefMap = fieldDefs.reduce(function(obj, def) { 
+    var field = def[0];
+    var tag = def[1];
+    obj[field] = {
+        field: field,
+        id: field,
+        tags: tag
+    };
+    return obj;
+}, {});
+function idToColumnDef(colId) {
+    return columnDefMap[colId] || null;
+}
+
+var fields = Object.keys(columnDefMap);
+var availableColumns = Object.values(columnDefMap);
+
+var records = DataGenerator.generateRecords(fields, { seed: 1, numRows: 20 });
+var configObj = {
+    staticDataRows: records
 };
 
 var grid = document.getElementById("grid");
 grid.config = configObj;
-
-

Listening an event

-

If you want to do a custom task after the dialog has been commited, you can listen for dialogCommitted event from Row Filtering Extension. The change from the dialog will be passed as value property in the event argument.

-
var onDialogCommitted = function (e) {
-    if(e.value) { // When user confirm dialog
-        console.log(e)
-    } else { // When user sort data from dialog
-        console.log(e);
-    }
+grid.columns = availableColumns.slice(0, 4);
+
+function onConfirm(e) {
+    grid.columns = e.detail.value;
 }
 
-var gridConfig = {
-    rowFiltering: {
-        dialogCommitted: onDialogCommitted
-    }
-};
+var dialog = null;
+document.getElementById("open_btn").addEventListener("click", function () {
+    if (!dialog) {
+        dialog = document.createElement("column-selection-dialog");
 
-// Alternatively
-rowFilteringExt.addEventListener("dialogCommitted", onDialogCommitted);
+        dialog.config = {
+            data: availableColumns,
+            confirm: onConfirm,
+            tags: availableTags,
+            infoTooltip: "Search Column to add to the right list. Press Tab to add a Tag. Available tags for Search: Red, Blue, Green, Runner, Swimmer, and Flier",
+            searchPlaceholder: "Search Column. Press Tab to add a Tag"
+        };
+    }
+    
+    var columnIds = grid.api.getColumnIds();
+    dialog.visibleItems = columnIds.map(idToColumnDef);
+    
+    dialog.show();
+});
 
-

API Reference

-

FilterDialog()

Type Definitions

-
typedef

ComboBoxItem

Type:
Object
Properties:
Name Type Description
label string text of item
value string value of item when item is selected
-
typedef

Config

Type:
Object
Properties:
Name Type Attributes Default Description
data Object Column data
sortState string <optional>
"a" for ascending or "d" for descending
sortUI boolean <optional>
true Show Sort area
filterUI boolean <optional>
true Show Filter area
advancedFilter boolean <optional>
true Show advanced tab
compactMode boolean <optional>
false Force compact mode in dialog
dateTimeFormat string <optional>
"dd-MM-yy" Specifies the string format for the date time picker in the filter dialog based on date-fns format, follow https://date-fns.org/v3.6.0/docs/format.
blankValues string | boolean <optional>
false Display a Blanks item in the filter dialog to represent an empty value. If a string is passed, it will be used as the label for the blank item
filterChanged function <optional>
Filter changed handler
confirm function <optional>
Alias of filterChanged
cancel function <optional>
Alias of dialog cancel
sortChanged function <optional>
Sort changed handler

Methods

+

API Reference

+

ColumnSelectionDialog()

Type Definitions

+
typedef

Config

Type:
Object
Properties:
Name Type Attributes Default Description
data Array.<Object> All possible columns for selection.
visibleItems Array.<Object> <optional>
Column list that is in existing Grid.
defaultItems Array.<Object> <optional>
Column list that is default.
confirm function <optional>
Confirm event callback.
cancel function <optional>
Cancel event callback.
excludedColumns number <optional>
Deprecated, Alias wigh excludedLeftColumns.
excludedLeftColumns number <optional>
Number of columns on the left side that should be hidden from Visible Columns.
excludedRightColumns number <optional>
Number of columns on the right side that should be hidden from Visible Columns.
unmovableColumns number <optional>
Depricated, Alias with stationary column option. Number of columns that is unmovable in Visible Columns.
descriptionBox boolean <optional>
Show description box
middleSeparator string <optional>
Field of column which used as middle separator to divide grid into two sides
collapseAll boolean <optional>
false Default collapse property applies to all groups
width number <optional>
Specify width of the dialog, with the minimum width of 490px
height number <optional>
Specify height of the dialog
tags Array.<string> <optional>
null All available tags for filtering
infoTooltip string <optional>
"" If specified, an informational icon will appear on the top with the given text as its tooltip
searchPlaceholder string <optional>
"Search" Placeholder text inside the search input.

Methods

function

hide()

Hide the dialog
-
function

hideSortUI(val)

Hide Sort UI block
Parameters:
val
boolean
value
-
function

init(options)

Initialize dialog
Parameters:
options
initial data
-
function

setSortState(val)

Parameters:
val
string
Sorting state "d" or "a"
-
function

show()

Show the dialog as a popup
\ No newline at end of file +
function

init(optionsopt)

Parameters:
options
<optional>
+
function

show()

Show the dialog
\ No newline at end of file diff --git a/template-154.html b/template-154.html index 321ea625..249b2d64 100644 --- a/template-154.html +++ b/template-154.html @@ -1,47 +1,326 @@ -

Internationalization

-

Widgets support localization, including translated messages and formatting. In your app, setting your html lang attribute will trigger that language to be applied to widget elements.

-
<html lang="ja">
-
-</html>
-
-

Alternatively, setting the lang attribute directly on elements will have the same effect.

-
-

lang on an element supersedes the html lang, meaning multiple languages can exist on the same page.

-
-
var dialog = document.createElement("column-selection-dialog");
-dialog.lang = "ja";
-
-

Currently, the following languages are supported:

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Languagelang value
English (default)en
Japaneseja
Germande
Simplified Chinesezh
Traditional Chinesezh-Hant
-
-

If an unsupported language is set, English is the default fallback.

-
-

Element Framework

-

More details about localization is avaiable on Internationalization

+ + +

Filter Dialog

+

The Filter Dialog is a user-friendly interface for filtering and sorting. The example below shows how Filter Dialog can be used in conjunction with Row Filtering Extension. Users can hover over column header to show filter icon. Clicking on the icon will open Filter Dialog.

+
body {
+    padding: 2px;
+}
+efx-grid {
+    height: 500px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 });
+var configObj = {
+    columns: [
+        { name: "Company", field: fields[0] },
+        { name: "Market", field: fields[1], width: 120 },
+        { name: "Last", field: fields[2], width: 100 },
+        { name: "Net. Chng", field: fields[3], width: 100 },
+        { name: "Industry", field: fields[4] }
+    ],
+    staticDataRows: records,
+    rowFiltering:{
+        iconActivation: "onHover"
+    },
+    extensions: [
+        new RowFiltering()
+    ]
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+

Setup guide

+
 // efx-grid
+import "@refinitiv-ui/efx-grid";
+import "@refinitiv-ui/efx-grid/themes/halo/light";
+
+// Extensions
+import { RowFiltering } from "@refinitiv-ui/efx-grid/extensions";
+
+// Filter Dialog module
+import "@refinitiv-ui/efx-grid/filter-dialog";
+import "@refinitiv-ui/efx-grid/filter-dialog/themes/halo/light";  // !Important. Theme must be imported.
+
+

The dialog cannot be used without Row Filtering Extension. So, initialize Row Filtering Extension instance and add it to extensions property on the grid configuration object. To open the dialog, you can either use iconActivation property or openDialog method from the extension.

+
var rowFilteringExt = new RowFiltering();
+
+var configObj = {
+    extensions: [
+        rowFilteringExt
+    ],
+    rowFiltering:{
+        iconActivation: "onHover"
+    },
+    columns: columns, // Columns config
+    staticDataRows: records
+};
+
+var grid = document.getElementById("grid_id");
+grid.config = configObj;
+
+function onClickButton(e) {
+  rowFilteringExt.openDialog(columnIndex);
+}
+
+

Advanced condition tab

+

Filter dialog has three types of condition tabs: generic value condition (default), numeric value condition, and date time value condition. Each type has a different list of available operators. For example, numeric value condition contains only nemeric operators, such as Less than or Greater than operators. To specify the type for the dialog, define fieldDataType property on the column configuration object to one of the following values: number, datetime, and text or nothing (default).

+
efx-grid {
+    height: 500px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "CF_NETCHNG", "ISODate"];
+var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 });
+var configObj = {
+    columns: [
+        { name: "Company", field: "companyName" },
+        { name: "Company (text)", field: "companyName", fieldDataType: "text" },
+        { name: "Date (generic)", field: "ISODate", width: 180 },
+        { name: "Date (datetime)", field: "ISODate", width: 180, fieldDataType: "datetime" },
+        { name: "Change (generic)", field: "CF_NETCHNG", width: 130 },
+        { name: "Change (number)", field: "CF_NETCHNG", width: 130, fieldDataType: "number" }
+    ],
+    staticDataRows: records,
+    rowFiltering:{
+        iconActivation: "onHover"
+    },
+    extensions: [
+        new RowFiltering()
+    ]
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+

Dialog options

+

Filter Dialog can be customized by setting dialogOptions property on the Row Filtering Extension configuration object as shown in the following code snippet:

+
var configObj = {
+    rowFiltering: {
+        dialogOptions: {
+            sortUI: false
+        }
+    }
+};
+
+

The options will be applied for every column in the grid. The options can be overriden on a column basis by using beforeDialogOpened event. You can specify dialogOptions property on the event argument and override the options set on the grid level as shown in the following code snippet:

+
var configObj = {
+    rowFiltering: {
+        dialogOptions: {
+            sortUI: false
+        },
+        beforeDialogOpened: function(e) {
+            if(e.field === "field A") {
+                e.dialogOptions = {
+                    sortUI: true
+                };
+            }
+        }
+    }
+};
+
+

Customizing filter item list

+

By default, the item list in Filter Dialog is generated from existing data on the column, where the dialog is openned. Any duplicate value is automatically removed from the list. If there is formatting applied by Text Formatting Extension on the column, the items will also be formatted.

+

itemList property on the dialog options can be used to replace the autogenerated one. This is useful when you want to prevent some values from being available for filtering.

+

additionalItems property on the dialog options can be used to add more values to the existing list. The property can be used to include some nonexistent values (e.g., you have some server side filtering).

+

formattedDataAccessor property on the dialog options allows you to specify a method for transforming and displaying items on the list. The method will be called on each item and it should return the formatted text you want to display in the dialog. The method can also be used to retrieve data from an object (i.e., data with non-premitive data type).

+

sortLogic property on the dialog options allows you to specify a method for reordering items on the list. The method will be used by Array.sort method

+
efx-grid {
+    height: 300px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var sortIdInDescendingOrder = function(valA, valB) {
+    if(valA < valB) {
+        return 1;
+    }
+    if(valB < valA) {
+        return -1;
+    }
+    return 0;
+};
+var booleanToYesNo = function(val) {
+    if(val != null) {
+        return val ? "Yes" : "No";
+    }
+    return "";
+};
+var onBeforeDialogOpened = function(e) {
+    var colIndex = e.colIndex;
+    if(colIndex === 0) { // id
+        e.dialogOptions = {
+            sortLogic: sortIdInDescendingOrder
+        };
+    } else if(colIndex === 2) { // replacement
+        e.dialogOptions = {
+            itemList: ["Left", "Center", "Right"]
+        };
+    } else if(colIndex === 3) { // addition
+        e.dialogOptions = {
+            additionalItems: [1, 0, "N/A"]
+        };
+    } else if(colIndex === 4) { // formatted
+        e.dialogOptions = {
+            formattedDataAccessor: booleanToYesNo
+        };
+    }
+};
+var fields = ["id", "boolean"];
+var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 10 });
+var configObj = {
+    rowFiltering: {
+        iconActivation: "onHover",
+        beforeDialogOpened: onBeforeDialogOpened
+    },
+    columns: [
+        { name: "Id", field: "id", width: 80 },
+        { name: "Boolean (default)", field: "boolean"},
+        { name: "Boolean (replacement)", field: "boolean"},
+        { name: "Boolean (addition)", field: "boolean"},
+        { name: "Boolean (formatted)", field: "boolean"}
+    ],
+    staticDataRows: records,
+    extensions: [
+        new RowFiltering()
+    ]
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+

Changing dialog language

+

For more information about internationalization and how is it applied in different contexts see Language Support.

+

Opening Filter Dialog using an API

+

The dialog can be openned from anywhere, not just from filter icon on the column header. Use openDialog method from Row Filtering extension instance, so that the dialog can be openned for specific column and linked up with grid instance.

+

The following example illustrates how the dialog can be opened from context menu using Context Menu Extension. Right click on the column header to see the dialog.

+
html hr {
+    margin: 5px;
+}
+efx-grid {
+    height: 500px;
+}
+
+
Language:
+<select id="lang_selector">
+    <option value="en">English</option>
+    <option value="ja">Japanese</option>
+    <option value="de">German</option>
+    <option value="zh">Simplified Chinese</option>
+    <option value="zh-Hant">Traditional Chinese</option>
+</select>
+<hr>
+<efx-grid id="grid"></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var rowFilteringExt = new RowFiltering();
+var contextMenuExt = new ContextMenu();
+
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "ISODate"];
+var records = DataGenerator.generateRecords(fields, { numRows: 10 });
+var configObj = {
+    columns: [
+        {name: "Company", field: fields[0], sortable: true, fieldDataType: "text"},
+        {name: "Market", field: fields[1], width: 100, sortable: true, fieldDataType: "text"},
+        {name: "Last", field: fields[2], width: 100, sortable: true, fieldDataType: "number"},
+        {name: "Net. Chng", field: fields[3], width: 100, sortable: true, fieldDataType: "number"},
+        {name: "IPO Date", field: fields[4], sortable: true, fieldDataType: "datetime"}
+    ],
+    staticDataRows: records,
+    contextMenu: {
+        items: {
+            MENU_1: {
+                text: "Filter",
+                callback: function (e) {
+                    var colIndex = e.colIndex;
+                    var lang = document.getElementById("lang_selector").value;
+                    var dialogOptions = {
+                        sortUI: true, // Show sorting section
+                        filterUI: true, // Show filtering section
+                        lang: lang,
+                        fieldDataType: grid.api.getColumnDataType(colIndex)
+                    };
+                    rowFilteringExt.openDialog(colIndex, dialogOptions);
+                }
+            },
+        },
+        onMenu: function (e) {
+            e.menu.addItem("MENU_1");
+        }
+    },
+    extensions: [
+        rowFilteringExt,
+        contextMenuExt
+    ]
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+

Listening an event

+

If you want to do a custom task after the dialog has been commited, you can listen for dialogCommitted event from Row Filtering Extension. The change from the dialog will be passed as value property in the event argument.

+
var onDialogCommitted = function (e) {
+    if(e.value) { // When user confirm dialog
+        console.log(e)
+    } else { // When user sort data from dialog
+        console.log(e);
+    }
+}
+
+var gridConfig = {
+    rowFiltering: {
+        dialogCommitted: onDialogCommitted
+    }
+};
+
+// Alternatively
+rowFilteringExt.addEventListener("dialogCommitted", onDialogCommitted);
+
+

API Reference

+

FilterDialog()

Type Definitions

+
typedef

ComboBoxItem

Type:
Object
Properties:
Name Type Description
label string text of item
value string value of item when item is selected
+
typedef

Config

Type:
Object
Properties:
Name Type Attributes Default Description
data Object Column data
sortState string <optional>
"a" for ascending or "d" for descending
sortUI boolean <optional>
true Show Sort area
filterUI boolean <optional>
true Show Filter area
advancedFilter boolean <optional>
true Show advanced tab
compactMode boolean <optional>
false Force compact mode in dialog
dateTimeFormat string <optional>
"dd-MM-yy" Specifies the string format for the date time picker in the filter dialog based on date-fns format, follow https://date-fns.org/v3.6.0/docs/format.
blankValues string | boolean <optional>
false Display a Blanks item in the filter dialog to represent an empty value. If a string is passed, it will be used as the label for the blank item
filterChanged function <optional>
Filter changed handler
confirm function <optional>
Alias of filterChanged
cancel function <optional>
Alias of dialog cancel
sortChanged function <optional>
Sort changed handler

Methods

+
function

hide()

Hide the dialog
+
function

hideSortUI(val)

Hide Sort UI block
Parameters:
val
boolean
value
+
function

init(options)

Initialize dialog
Parameters:
options
initial data
+
function

setSortState(val)

Parameters:
val
string
Sorting state "d" or "a"
+
function

show()

Show the dialog as a popup
\ No newline at end of file diff --git a/template-155.html b/template-155.html new file mode 100644 index 00000000..321ea625 --- /dev/null +++ b/template-155.html @@ -0,0 +1,47 @@ +

Internationalization

+

Widgets support localization, including translated messages and formatting. In your app, setting your html lang attribute will trigger that language to be applied to widget elements.

+
<html lang="ja">
+
+</html>
+
+

Alternatively, setting the lang attribute directly on elements will have the same effect.

+
+

lang on an element supersedes the html lang, meaning multiple languages can exist on the same page.

+
+
var dialog = document.createElement("column-selection-dialog");
+dialog.lang = "ja";
+
+

Currently, the following languages are supported:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Languagelang value
English (default)en
Japaneseja
Germande
Simplified Chinesezh
Traditional Chinesezh-Hant
+
+

If an unsupported language is set, English is the default fallback.

+
+

Element Framework

+

More details about localization is avaiable on Internationalization

diff --git a/template-46.html b/template-46.html index d12d193b..0920c18f 100644 --- a/template-46.html +++ b/template-46.html @@ -98,7 +98,7 @@

Initializing segments

Initializing segments by using segment id field example

Use segmentIdField to specify which value of the field in the row data to be used for segmentation. The following code snippet shows possible setups for row segmenting:

-
var records = [ // For illustration purpose
+
var records = [ // For illustrative purpose
     {}, // normal row
     {}, // normal row
     {"segmentId": "1"}, // group header row / segment separator
@@ -249,7 +249,7 @@ 

Dragging group header

Nested segments (multi-level segments)

Use parentIdField option to specify which value of the field in the row data to be used for specifying parent of the row. segmentIdField still be used to specify group header/segment separator. The following code snippet shows possible setups for row segmenting:

-
var records = [ // For illustration purpose
+
var records = [ // For illustrative purpose
     {}, // normal row
     {}, // normal row
     {"segmentId": "1"}, // segment 1
@@ -269,7 +269,7 @@ 

Dragging group header

};

For normal rows (non segment separator rows), value from segmentIdField field is not required. We can simplify the above code snippet as the one below:

-
var records = [ // For illustration purpose
+
var records = [ // For illustrative purpose
     {}, // normal row
     {}, // normal row
     {"segmentId": "1"                 }, // segment 1
diff --git a/template-62.html b/template-62.html
index ecc10d42..ac8594c2 100644
--- a/template-62.html
+++ b/template-62.html
@@ -477,7 +477,7 @@ 

Single click for editing

typedef

Cache

Stored all important object relate to column that need to use in this plugin.
Type:
Object
Properties:
Name Type Description
editor Element Container element of input.
balloonPopup Element balloon popup. It contains balloon element inside.
inputElement Element Input element such as text input, numeric stepper, date-time picker.
typedef

ColumnOptions

Column options that can be specified on each individual grid's column option:
Type:
Object
Properties:
Name Type Attributes Default Description
editableContent boolean <optional>
false Make the column editable by double click
inCellEditing InCellEditingPlugin~EditorOptions <optional>
Editor options give more refinements, such as "type" for specific editor type or "entries" for dropdown box
typedef

EditorOptions

Editor options specified through `inCellEditing` property on the column configuration object
Type:
Object
Properties:
Name Type Attributes Default Description
type string <optional>
"text" Specify type of the editor. Available types are text, number, dropdown, date, checkbox, and combobox.
entries Array <optional>
null Specify list of items available in the dropdown box
attributes Object <optional>
null Specify attribute of input element
-
typedef

Options

InCellEditingPlugin options that can be specified from `inCellEditing` property of the main grid's options
Type:
Object
Properties:
Name Type Attributes Default Description
balloonMode boolean <optional>
false Show editor in a balloon. This is useful when there is not much space in the cell
editableTitle boolean <optional>
false If enabled, all column headers can be edited by double click
editableContent boolean <optional>
false If enabled, all content cells can be edited by double click. This can be overridden individual column configuration.
autoCommitText boolean <optional>
false If enabled, the text will be committed even if user leaving editor midway
dataBinding boolean <optional>
true If disabled, text will not be updated in the grid's data table
popupElement Element <optional>
null Element to be attached under the editor
doubleClick boolean <optional>
true If disabled, double click will not trigger editor
tabToMove boolean <optional>
false If enabled, pressing tab key while editor is active will open editor on the next editable cell.
contentSource string <optional>
"textContent" By default, the text in the editor will be populated with textContent of the target cell. Use "field" to populated data from grid's data model. Use "empty" to shows empty editor.
inlineStyling boolean <optional>
false force inline styles regardless of elf version.
disablingScroll boolean <optional>
false Scrollbar will be frozen when editor opened. Deprecated in favor of uiBlocking
uiBlocking boolean <optional>
false append transparent overlay to block ui interaction
preEditorOpening function <optional>
null Handler before editor is opened
editorOpened function <optional>
null Handler after editor is opened
beforeCommit function <optional>
null Handler before data binding, allowing data type conversion
editorClosed function <optional>
null Handler after editor is closed
keyUp function <optional>
null Handler for each keyup of the input text box
beforeRowCommit function <optional>
null Handler before committing from all editors in the row
rowEditorClosed function <optional>
null Handler after closing of all editors
autoSuggest Element <optional>
null Element of ef-autosuggest or atlas-autosuggest for handled with input cell
closingOnScroll boolean <optional>
true If disabled, the editor will not be automatically closed when scrolling grid.
autoHiding boolean <optional>
true If disabled, the editor will not be automatically closed when losing its focus.
readonly boolean <optional>
false If disabled, the editor will not be able to open, this property overwrite `editableContent` and `editableTitle`
starterText string | boolean <optional>
false if enable it, it will be show placeholder when no ric in grid, given string to overwrite wording

Methods

+
typedef

Options

InCellEditingPlugin options that can be specified from `inCellEditing` property of the main grid's options
Type:
Object
Properties:
Name Type Attributes Default Description
balloonMode boolean <optional>
false Show editor in a balloon. This is useful when there is not much space in the cell
editableTitle boolean <optional>
false If enabled, all column headers can be edited by double click
editableContent boolean <optional>
false If enabled, all content cells can be edited by double click. This can be overridden individual column configuration.
autoCommitText boolean <optional>
false If enabled, the text will be committed even if user leaving editor midway
dataBinding boolean <optional>
true If disabled, text will not be updated in the grid's data table
popupElement Element <optional>
null Element to be attached under the editor
doubleClick boolean <optional>
true If disabled, double click will not trigger editor
tabToMove boolean <optional>
false If enabled, pressing tab key while editor is active will open editor on the next editable cell.
contentSource string <optional>
"textContent" By default, the text in the editor will be populated with textContent of the target cell. Use "field" to populated data from grid's data model. Use "empty" to shows empty editor.
inlineStyling boolean <optional>
false force inline styles regardless of elf version.
disablingScroll boolean <optional>
false Scrollbar will be frozen when editor opened. Deprecated in favor of uiBlocking
uiBlocking boolean <optional>
false append transparent overlay to block ui interaction
preEditorOpening function <optional>
null Handler before editor is opened
editorOpened function <optional>
null Handler after editor is opened
beforeCommit function <optional>
null Handler before data binding, allowing data type conversion
editorClosed function <optional>
null Handler after editor is closed
keyUp function <optional>
null Handler for each keyup of the input text box
beforeRowCommit function <optional>
null Handler before committing from all editors in the row
rowEditorClosed function <optional>
null Handler after closing of all editors
autoSuggest Element <optional>
null Element of ef-autosuggest or efx-autosuggest for handled with input cell
closingOnScroll boolean <optional>
true If disabled, the editor will not be automatically closed when scrolling grid.
autoHiding boolean <optional>
true If disabled, the editor will not be automatically closed when losing its focus.
readonly boolean <optional>
false If disabled, the editor will not be able to open, this property overwrite `editableContent` and `editableTitle`
starterText string | boolean <optional>
false if enable it, it will be show placeholder when no ric in grid, given string to overwrite wording

Methods

function

_getRowIndex(rowId) → {number}

Parameters:
rowId
string
Returns:
number
row index will return -1 if not found
function

_requestUpdateStarterText()

Request to show starter text
function

appendText(word)

Use to append text in text editor. WARNING: Only works with the text type editor
Parameters:
word
string
@@ -498,7 +498,7 @@

Single click for editing

function

enableTitleEditing(opt_enabledopt)

Parameters:
opt_enabled
boolean
<optional>
function

getActiveColIndex() → {number}

get active column index that editor had opended. Function can work only in cell editing mode.
Returns:
number
column index will return -1 if not found
function

getActiveRowIndex() → {number}

get active row index that editor had opended. Function Can work in both cell/row editing modes.
Returns:
number
row index will return -1 if not found
-
function

getAutoSuggest() → {Element}

Get ef-autosuggest or atlas-autosuggest
Returns:
Element
+
function

getAutoSuggest() → {Element}

Get ef-autosuggest or efx-autosuggest
Returns:
Element
function

getBalloonPopup() → {Popup|null}

Get Balloon Popup Element to access any API provided.
Returns:
Popup | null
function

getConfigObject(out_objopt) → {Object}

Get a current state of grid and extension config
Parameters:
out_obj
Object
<optional>
Returns:
Object
function

getInitialText() → {string}

Returns:
string
@@ -545,7 +545,7 @@

Single click for editing

} });
event

editorClosed

Fired after the text editor has been closed and all operations are done. This is useful to clean up left over resource and get result text entered.
Type:
Object
Properties:
Name Type Attributes Description
text string <optional>
Text that user has entered
groupHeader boolean <optional>
This value is set to true if the editing row is a group header.
segmentSeparator boolean <optional>
This value is set to true if the editing row is a segment separator.
suggestionDetail Object Suggestion detail for auto suggest "item-select" event
cancelled boolean Readonly flag. Indicates whether the commit operation has been cancelled
committed boolean Readonly flag. The opposite of `cancelled` flag
-
event

editorOpened

Fired after the opening of text editor. Any visual customization can be done at this stage, including the text shown in the editor.
Type:
Object
Properties:
Name Type Description
dataSource Object DataView
rowIndex number
field string
inputElement Element
autoSuggest Element ef-autosuggest or atlas-autosuggest
Example:
let cep = new InCellEditingPlugin();
+
event

editorOpened

Fired after the opening of text editor. Any visual customization can be done at this stage, including the text shown in the editor.
Type:
Object
Properties:
Name Type Description
dataSource Object DataView
rowIndex number
field string
inputElement Element
autoSuggest Element ef-autosuggest or efx-autosuggest
Example:
let cep = new InCellEditingPlugin();
 cep.listen("editorOpened", function(e) {
   let data = e.dataSource.getDataAt(e.rowIndex, e.field);
   e.inputElement.value = data + " aaa";
diff --git a/template-66.html b/template-66.html
index 62dae54d..e4b94d84 100644
--- a/template-66.html
+++ b/template-66.html
@@ -63,8 +63,8 @@ 

Custom dragbox

Draging a row to the bottom of Grid

You can drag a row to the bottom of Grid by moving the mouse over the bottom half of the last row. The dragged row will be moved and put as the last row. Sometimes, the bottom half of the row can be small and difficult to place your mouse over. You can try to expand Grid's area beyond the last row to mitigate the issue, as the extension allows any drag and drop operation within Grid's area.

Extending Grid's area example

-
body {
-    height: 500px; /* for illustration purpose */
+
body {
+    height: 500px; /* for illustrative purpose */
     padding: 4px;
     box-sizing: border-box;
 }
diff --git a/template-70.html b/template-70.html
index 30c8fc99..2ac8f9b0 100644
--- a/template-70.html
+++ b/template-70.html
@@ -2,7 +2,7 @@
 
 

Row Coloring

The Row Coloring Extension provides a way to set text color and background color in each row.

-
efx-grid {
+
efx-grid {
     height: 169px;
 }
 
@@ -21,7 +21,7 @@

Row Coloring

var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 5 }); -// Colors are set for illustration purpose +// Colors are set for illustrative purpose records[1]["txtField"] = "#334444"; records[1]["bgcField"] = "#dcdc88"; @@ -54,7 +54,7 @@

Row Coloring

Installation examples and details of how to import the extension to a project are available on the Overview page.

Defining row color based on row data

The extension supports setting text color and background color through data in a row. When there is an operation that shifts data around, such as sorting and filtering, the colors will be moved along with their corresponding rows. To define the color, use bgColorField and textColorField properties in the rowColoring option to indicate which field to be used in the row data.

-
efx-grid {
+
efx-grid {
     height: 169px;
 }
 
@@ -83,7 +83,7 @@

Defining row color based on row da var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 5 }); -// Colors are set for illustration purpose +// Colors are set for illustrative purpose records[1]["colorField"] = "color-1"; records[3]["colorField"] = "color-2"; @@ -157,7 +157,7 @@

Having both row and column "A": {} };

-
efx-grid {
+
efx-grid {
     height: 200px;
 }
 
@@ -192,7 +192,7 @@

Having both row and column var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 6 }); -// Colors are set for illustration purpose +// Colors are set for illustrative purpose records[1]["coloringClass"] = "color-1"; records[3]["coloringClass"] = "highestPriority"; @@ -214,7 +214,7 @@

Having both row and column name: "Net. Chng", field: "CF_NETCHNG", width: 100, conditions: [ { - expression: "[CF_NETCHNG]", // For illustration purpose + expression: "[CF_NETCHNG]", // For illustrative purpose cssClass: "myRedColor" } ] diff --git a/template-81.html b/template-81.html index 85b782c6..941fcc4e 100644 --- a/template-81.html +++ b/template-81.html @@ -1,6 +1,6 @@

Event Listeners

Since Grid is element, you can directly listen for events from it. It's recommended to listen for native events and then use the getRelativePosition() method to resolve which cell, area, or position are the target of the event. This is because Grid does not render every cell, and the cells are being reused across different rows. So it's important to resolve the position inside the event handler (such as, runtime resolving). You can use any native event and resolve the position by using the getRelativePosition() method.

-

Click

+

Click and right click

If you want to do something on the click event, you could do the following code snippet:

var grid = document.getElementById("grid_id");
 
@@ -10,29 +10,14 @@ 

Click

console.log(pos.sectionType, pos.colIndex, pos.rowIndex); // pos object contains a lot of information });
-

Right click

-

Simply use native contextmenu event to detect right click on the grid element. Use preventDefault() method to prevent default context menu behaviors from triggering.

-

Mouse events

-

The common native events, such as mousemove, mouseup, and mousedown, can be listened on the grid element.

-
-

Note: Grid internally divides itself into several sections. The top section is called title and the lower part is called content. So the sectionType from the position object can be one of the following values: title, content, footer.

-
-

Listening to native events example

-
html hr {
-    margin: 5px;
-}
-textarea {
-    width: 100%;
-    height: 80px;
-    font-size: 20px;
-}
-efx-grid {
+

For right click, simply use native contextmenu event to detect right click on the grid element. Use preventDefault() method to prevent default context menu behaviors from triggering.

+

Listening to click and right click events example

+

The below example shows how you can click or right click on the grid element to get information about the clicked position.

+
efx-grid {
     height: 300px;
 }
 
-
<textarea id="msg_ta"></textarea>
-<hr>
-<efx-grid></efx-grid>
+
<efx-grid></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -64,6 +49,7 @@ 

Listening to native events exampleListening to native events exampleListening to native events example

+

Mouse events

+

The common native events, such as mousemove, mouseup, and mousedown, can be listened on the grid element.

+

Listening to mousemove event example

+
html hr {
+    margin: 5px;
+}
+textarea {
+    width: 100%;
+    height: 80px;
+    font-size: 20px;
+}
+efx-grid {
+    height: 300px;
+}
+
+
<textarea id="msg_ta"></textarea>
+<hr>
+<efx-grid></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["id", "companyName", "market", "CF_NETCHNG", "CF_VOLUME"];
+var columnNames = ["Id", "Company Name", "Market", "Net Chng.", "Volume"];
+var columns = fields.map(function(f, idx) {
+    return {
+        field: f,
+        name: columnNames[idx]
+    }
+});
+var records = DataGenerator.generateRecords(fields, {seed: 1, rowCount: 20});
+
+var configObj = {
+    columns: columns,
+    staticDataRows: records
+};
+var grid = document.getElementsByTagName("efx-grid")[0];
+grid.config = configObj;
+
 grid.addEventListener("mousemove", function(e) {
     var pos = grid.api.getRelativePosition(e);
     var ary = [
@@ -93,13 +127,75 @@ 

Listening to native events example

-

Getting a cell and its content

+

Keyboard events

+

Since Grid is not an interactive element, clicking grid does not give focus to it. You will need to call focus() method from Grid's APIs in order to give grid element the focus, allowing it to receive keyboard inputs/events.

+

Listening to keyup event example

+

The below example shows how you can listen to click event and give focus to grid for receiving keyboard input:

+
html body {
+    padding: 5px;
+    box-sizing: border-box;
+}
+html hr {
+    margin: 5px;
+}
+textarea {
+    width: 100%;
+    height: 40px;
+    font-size: 20px;
+}
+efx-grid {
+    height: 300px;
+}
+efx-grid:focus-within { /* For illustrative purpose */
+    outline-width: 1px;
+    outline-style: solid;
+    outline-color: blue;
+}
+
+
<textarea id="msg_ta"></textarea>
+<hr>
+<efx-grid></efx-grid>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["id", "companyName", "market", "CF_NETCHNG", "CF_VOLUME"];
+var columnNames = ["Id", "Company Name", "Market", "Net Chng.", "Volume"];
+var columns = fields.map(function(f, idx) {
+    return {
+        field: f,
+        name: columnNames[idx]
+    }
+});
+var records = DataGenerator.generateRecords(fields, {seed: 1, rowCount: 20});
+
+var configObj = {
+    columns: columns,
+    staticDataRows: records
+};
+var grid = document.getElementsByTagName("efx-grid")[0];
+grid.config = configObj;
+
+grid.addEventListener("click", function(e) {
+    grid.api.focus();
+});
+grid.addEventListener("keyup", function(e) {
+    msg_ta.value = "Key: " + e.key + ", Code: " + e.code;
+});
+
+

Getting a cell and its content

With row virtualization and column virtualization, Grid only renders cells that are on the current view. So, only cells and their content that are in range of the current view can be retrieved. To retrieve cell content, use getCoreGrid to get core grid instance first. Then, use getCell(section, colIndex, rowIndex) from the core to get cell object. Finally, use getContent() from the cell object to get the cell content. If you want all the data content (not the content elements), please use grid data related APIs instead.

If you are inside an event listener, the corresponding cell object is already provided from the returned value of getRelativePosition method. You can then get cell content from the cell object using getContent() method. Alternatively, you can use composedPath method from native event argument to get a path to actual target element.

Note: Grid is a custom element which encapusulate all of its content under its shadow root. Hence, target property from the native Event argument will always return Grid element and not actual target element inside the grid.

-

Getting cell content example

+

Getting cell content example

html hr {
     margin: 5px;
 }
diff --git a/template-92.html b/template-92.html
index 3ad5af4b..7464798e 100644
--- a/template-92.html
+++ b/template-92.html
@@ -1,37 +1,16 @@
-

Using Core APIs

-

Core Grid is the internal part of Grid, containing logics for UI and layout manipulation. Grid is just a wrapper that make the JavaScript grid component (Core Grid) become a custom element in the Web Components standard.

-

Some of the APIs are already propagated and exposed to the api property of the element. However, most of the APIs are still only available in the core part of Grid.

-

To unlock all the APIs you need to get a reference to the Core Grid by using the getCoreGrid method from api as shown in the below sample:

-
var grid = document.getElementsByTagName("efx-grid")[0];
-grid.addEventListener("configured", function(e) {
-    var core = e.detail.api.getCoreGrid(); // Getting Core Grid reference
-    
-    var titleSection = core.getSection("title");
-    var contentSection = core.getSection("content");
-    var colCount = core.getColumnCount();
-});
-
-
-

Note: The custom elements are not defined immediately after the page load. api will only be available after the element is defined. So, use the configured event to ensure the existence of the api property.

-
-

For all available Core Grid APIs, see this page.

-

Getting built-in plugins and extensions

-

Due to the long history of its development, Grid contains a lot of legacy codes, including built-in plugins. A plugin is just an old name for an extension. So, to get a reference for plugins or extensions, you can use the getPlugin method from the Core Grid.

-
-

Note: The "SortableTitlePlugin" is the only notable plugin worth mentioning among built-in plugins, since it manages how Grid sorts the data.

-
-

The following example shows how you can listen to the columnSorted event fired after each sorting state change from the SortableTitlePlugin.

-

Example

-
efx-grid {
-    height: 200px;
-}
-html hr {
-    margin: 5px;
+

Auto Suggest

+

If you have an input element inside the grid, we have provided a way to attach auto-suggest functionality to that input. This feature is helpful for users who want to type and search for something within the input field.

+

Cell editing

+

If you are using in-cell editing extensions, you can enable the auto-suggest feature by setting the autoSuggest option. This will display auto-suggestions when typing in the input field of the in-cell editing extension. Here is an example for you:

+
efx-grid {
+    height: 300px;
+    margin-bottom: 40px;
 }
 
-
<big id="msg_div">Click grid top section to sort</big>
-<hr>
-<efx-grid id="grid"></efx-grid>
+
<efx-grid id="grid_elem"></efx-grid>
+<div id="contain_elem">
+    <efx-autosuggest id="auto_suggest_elem"></efx-autosuggest>
+</div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -42,36 +21,957 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 6 }); +var inCellEditingExt = new InCellEditing(); -var onColumnSorted = function(e) { - msg_div.textContent = "Column " + e.colIndex + " is sorted in " + (e.sortOrder === "a" ? "ascending" : "descending") + " order"; -}; +var fields = ["RIC", "market", "CF_LAST", "industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 50 }); +var grid = document.getElementById("grid"); +records = records.map(function(record) { + record["RIC"] = ""; + return record; +}) +records[2]["RIC"] = "APPL.O"; +var rows = new Array(20).map(function (val) { + return ""; +}); +rows[2] = "APPL.O"; var configObj = { - sorting: { - sortableColumns: true, - }, + tabToFocus: true, columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 120}, - {name: "Last", field: fields[2], width: 100}, - {name: "Net. Chng", field: fields[3], width: 100}, - {name: "Industry", field: fields[4]} + { + field: fields[0], + name: "RIC (Double Click to edit cell)", + editableContent: true + }, + { + field: fields[1], + name: "Market" + }, + { + field: fields[2], + }, + { + field: fields[3], + name: "Industry" + } ], - staticDataRows: records + staticDataRows: records, + extensions: [inCellEditingExt], + inCellEditing: { + editableTitle: true, + editableContent: false, + autoSuggest: auto_suggest_elem + }, }; +var grid = window.grid = document.getElementById("grid_elem"); +grid.config = configObj; + +var autoSuggestElem = document.getElementById("auto_suggest_elem"); +autoSuggestElem.moreSearchDisabled = true; // Disable more search result, if you want to enable it follow https://amp.int.refinitiv.com/#/package/@elf/efx-autosuggest +// You can set other autosuggest options here, for example "api-key", "profile", "language", "ric", "country", "portfolioId", "filter", etc. +mockAutosuggestElementData(autoSuggestElem); +// ========== MOCK data server. Don't copy this section ================= + +function mockAutosuggestElementData(autoSuggestElem) { + + const flattenResponse = (response) => { + const { result, search, header, action } = response; + const suggestions = []; + const meta = { + url: search, + keyword: header.request.query + }; + if (result && result.length) { + result.forEach(row => { + const rowAsDefault = row.default === true; + const rowHits = row.hits; + if (rowHits && rowHits.length) { + rowHits.forEach((rowHit, hitIdx) => { + suggestions.push({ + label: rowHit.cmd, + value: rowHit, + highlighted: rowAsDefault && hitIdx === 0, + meta + }); + const relations = rowHit.relations; + if (relations) { + Object.keys(relations).forEach(key => { + const relation = relations[key]; + const relationAsDefault = relation.default === true; + const relationHits = relation.hits; + if (relationHits && relationHits.length) { + relationHits.forEach((relationHit, relationHitIdx) => { + suggestions.push({ + label: relationHit.cmd, + value: relationHit, + parent: rowHit, + asSub: true, + highlighted: relationAsDefault && relationHitIdx === 0, + meta + }); + }); + } + }); + } + }); + } + }); + } + return { + header, + meta, + suggestions, + action, + searchUrl: search + }; + }; + autoSuggestElem.addEventListener("suggestions-fetch-requested", suggest); + function suggest(ev) { + // Stop default data fetching + + ev.preventDefault(); + + // construct cache key off the query object + var cacheKey = JSON.stringify(ev.detail.query); + + // (optional) use util to parse response + var responseData = { + "header": { + "request": { + "filter": "", + "highlight": true, + "userProfileAssetClass": "CSH", + "api-key": "czZTQ5MjY4", + "eikon_version": "Eikon Web", + "profile": "AlertsUI2", + "query": "IBV", + "uuid": "PATESTCPA724", + "appl_category": [] + }, + "response": { + "duration": 57, + "server": "c962fkkaswb04.int.thomsonreuters.com", + "num_results": 10 + } + }, + "result": [ + { + "name": "Equities", + "hits": [ + { + "score": 6867489, + "navigation": null, + "id": "1097326", + "title": "International Business Vehicle Corp", + "subtitle": "Ordinary Share - NYSE Consolidated - IBV", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "", + "cmd": "IBV", + "relations": {}, + "position": 0, + "source": "12", + "explanation": null, + "p": { + "RIC": "IBV", + "IsChain": false, + "PermID": "55839165994", + "OAPermID": "4295904307" + }, + "ac": [ + "A:1", + "A:1L" + ], + "s": "IBV", + "vc": "EQ", + "fr": false, + "st": "RIC", + "preview": true + }, + { + "score": 2762007, + "navigation": null, + "id": "131770829", + "title": "International Business Vehicle Corp", + "subtitle": "Ordinary Share - MiFID Composite Cross Market Service - IBV", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "IUSD.xbo", + "cmd": "IBVIUSD.xbo", + "relations": {}, + "position": 1, + "source": "12", + "explanation": null, + "p": { + "RIC": "IBVIUSD.xbo", + "IsChain": false, + "PermID": "21523029548", + "OAPermID": "4295904307" + }, + "ac": [ + "A:1", + "A:1L" + ], + "s": "IBVIUSD.xbo", + "vc": "EQ", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 2, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllEquities&Search.Value=ibV" + }, + { + "name": "Funds", + "hits": [ + { + "score": 2741047, + "navigation": null, + "id": "298223588", + "title": "iShares iBonds Dec 2024 Term Muni Bond ETF", + "subtitle": "Bond ETF - US123712312 - USD - Cboe Consolidated - IBVM", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "M.K", + "cmd": "IBVM.K", + "relations": {}, + "position": 4, + "source": "24", + "explanation": null, + "p": { + "RIC": "IBVM.K", + "IsChain": false, + "PermID": "21642135445", + "lipperId": "40215430" + }, + "ac": [ + "A:5", + "A:2X", + "A:L0", + "A:7", + "A:GL" + ], + "s": "IBVM.K", + "vc": "FND", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllFunds&Search.Value=ibV" + }, + { + "name": "Options", + "hits": [ + { + "score": 2157436, + "navigation": null, + "id": "585064349", + "title": "OPRA International Business Vehicle Equity Option 145 Call Oct 2022 - IBV", + "subtitle": "Equity Cash Option - OPRA - IBVJ2122C145000", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "J212214500.U", + "cmd": "IBVJ212214500.U", + "relations": {}, + "position": 5, + "source": "14", + "explanation": null, + "p": { + "RIC": "IBVJ212214500.U", + "IsChain": false, + "PermID": "21873654768" + }, + "ac": [ + "A:1", + "A:2K", + "A:1T", + "A:7", + "A:G1", + "A:60" + ], + "s": "IBVJ212214500.U", + "vc": "OPT", + "fr": false, + "st": "RIC", + "preview": false + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllOptions&Search.Value=ibV" + }, + { + "name": "Indices", + "hits": [ + { + "score": 2157150, + "navigation": null, + "id": "215781470", + "title": "INTL BUSINES Single Stock Dividend", + "subtitle": "Equity Index", + "symbol": "0#.IBVDIV", + "cmd": "0#.IBVDIV", + "relations": {}, + "position": 6, + "source": "7", + "explanation": null, + "p": { + "RIC": "0#.IBVDIV", + "OAPermID": "4298427948" + }, + "ac": [ + "M:D6", + "I:M", + "I:17", + "A:1" + ], + "s": "0#.IBVDIV", + "vc": "INDX", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllIndices&Search.Value=ibV" + }, + { + "name": "Commodities", + "hits": [ + { + "score": 1598945, + "navigation": null, + "id": "606788540", + "title": "Argus Ice Brent Month 2 Snapshot PA5000637", + "subtitle": "Crude Oil - Commodity Spot - ARGUS", + "symbol": "" + "<b>" + ev.detail.query + "</b>" + "SST=ARG", + "cmd": "IBVSST=ARG", + "relations": {}, + "position": 7, + "source": "15", + "explanation": null, + "p": { + "RIC": "IBVSST=ARG", + "IsChain": false, + "PermID": "21891574387" + }, + "ac": [ + "A:4", + "A:1Q" + ], + "s": "IBVSST=ARG", + "vc": "COM", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV" + }, + { + "name": "Fixed Income", + "hits": [ + { + "score": 1465259, + "navigation": null, + "id": "0x00102c80bf6b046c", + "title": "International Business Vehicle Corp - " + "<b>" + ev.detail.query + "</b>" + " 2.875% 09-Nov-2022", + "subtitle": "Plain Vanilla Fixed Coupon Bond - Underwritten", + "symbol": "US459200JC60", + "cmd": "US459200JC60", + "relations": {}, + "position": 8, + "source": "3", + "explanation": null, + "p": { + "RIC": "459200JC6=", + "OAPermID": "4295904307" + }, + "ac": [ + "A:2", + "A:J" + ], + "s": "459200JC6=", + "vc": "BOND", + "fr": false, + "st": "RIC", + "preview": true + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV" + }, + { + "name": "FX", + "hits": [ + { + "score": 237124, + "navigation": null, + "id": "47051538460", + "title": "US Dollar/Chinese Renminbi 6 Month FX Forecast", + "subtitle": "IBV INDIA - 6 Month", + "symbol": "CNY6MP=0631", + "cmd": "CNY6MP=0631", + "relations": {}, + "position": 9, + "source": "23", + "explanation": null, + "p": { + "RIC": "CNY6MP=0631", + "PermID": "47051538460" + }, + "ac": [ + "M:D6", + "A:55", + "A:3", + "A:9", + "M:1MN" + ], + "s": "CNY6MP=0631", + "vc": "FX", + "fr": false, + "st": "RIC", + "preview": false + } + ], + "hasMore": true, + "default": false, + "size": 1, + "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllFXMoney&Search.Value=ibV" + } + ], + "search": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV", + "action": "\"IBV\" SRCH", + "assetClassifierStatus": "NOT_INVOKED", + "assetClassifierExplanation": "Current profile is not in the list of the silent mode profiles for asset classifier." + }; + var parsed = flattenResponse(responseData); + + // cache the response + autoSuggestElem.cacheModel.set(cacheKey, parsed); + + // set suggestions data + autoSuggestElem.setSuggestions(parsed); + } +} +
+

Custom rendering

+

If you use custom rendering for inputs and want to attach the auto-suggest element to your input, you can do so even if you have multiple inputs inside the grid. When you focus on an input, the auto-suggest will automatically attach to that input, and suggestions will appear as you type. Here is an example for you:

+
efx-grid {
+    height: 300px;
+    margin-bottom: 40px;
+}
+
+
<efx-grid id="grid_elem"></efx-grid>
+<div id="contain_elem">
+    <efx-autosuggest id="auto_suggest_elem"></efx-autosuggest>
+</div>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["RIC", "market", "CF_LAST", "industry"];
+var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 22 });
+var simpleInputFormatter = tr.SimpleInputFormatter ? tr.SimpleInputFormatter: SimpleInputFormatter;
 
 var grid = document.getElementById("grid");
-grid.addEventListener("configured", function(e) {
-    var core = e.detail.api.getCoreGrid();
-    
-    var plugin = core.getPlugin("SortableTitle");
-    plugin.listen("columnSorted", onColumnSorted);
+records = records.map(function(record) {
+    record["RIC"] = "";
+    return record;
+})
+records[2]["RIC"] = "APPL.O";
+var rows = new Array(20).map(function (val) {
+    return "";
 });
+rows[2] = "APPL.O";
+
+var configObj = {
+    tabToFocus: true,
+    columns: [
+        {
+            field: fields[0],
+            name: "RIC",
+            binding: autoSuggestBinding,
+            focusable: true,
+        },
+        {
+            field: fields[1],
+            name: "Market",
+            binding:  simpleInputFormatter.create(),
+            focusable: true,
+        },
+        {
+            field: fields[2],
+        },
+        {
+            field: fields[3],
+            name: "Industry",
+            binding: simpleInputFormatter.create(),
+            focusable: true,
+        }
+    ],
+    staticDataRows: records
+};
+var grid = window.grid = document.getElementById("grid_elem");
 grid.config = configObj;
+
+function autoSuggestBinding(e) {
+    let cell = e.cell;
+    let rowData = e.rowData;
+    let rowDef = e.rowDef;
+    let rowIndex = e.rowIndex;
+    let content = cell.getContent();
+    if (!content || !content._inputElem) {
+        let inputElem = content = document.createElement("input");
+        inputElem.placeholder = 'Type to search RIC';
+        content._inputElem = inputElem;
+        inputElem.addEventListener("focus", onAttachingInputFocused);
+    }
+    content._inputElem.value = rowData[fields[0]] || "";
+    cell.setContent(content);
+};
+
+function onAttachingInputFocused(e, rowIndex) {
+    autoSuggestGlobe.attach = e.target;
+    autoSuggestGlobe.positionTarget = e.target;
+}
+
+function onValueChanged(e) {
+    console.log("Value Changed", e);
+}
+
+function onItemSelected(e) {
+    let autoSuggestElem = e.srcElement;
+    let inputAttaching = autoSuggestElem.attach;
+    let pos = grid.api.getRelativePosition(inputAttaching);
+    if(!pos || !pos.hit) { // Element not inside the grid
+        return;
+    }
+    let detail = e.detail;
+    let value = detail.suggestion.value;
+    if(!value) {
+        console.warn("Auto suggestion item has no value");
+        return;
+    }
+    let ric = value.p.RIC;
+    let rowIndex = pos.rowIndex;
+    let rowDef = grid.api.getRowDefinition(rowIndex);
+    rowDef.setData("RIC", ric);
+}
+var autoSuggestGlobe = document.getElementById("auto_suggest_elem");
+autoSuggestGlobe.moreSearchDisabled = true; // Disable more search result, if you want to enable it follow https://amp.int.refinitiv.com/#/package/@elf/efx-autosuggest
+// You can set other autosuggest options here, for example "api-key", "profile", "language", "ric", "country", "portfolioId", "filter", etc.
+autoSuggestGlobe.addEventListener("item-select", onItemSelected);
+
+mockAutosuggestElementData(autoSuggestGlobe);
+document.getElementById("contain_elem").appendChild(autoSuggestGlobe);
+// ========== MOCK data server. Don't copy this section =================
+
+function mockAutosuggestElementData(autoSuggestElem) {
+
+    const flattenResponse = (response) => {
+        const { result, search, header, action } = response;
+        const suggestions = [];
+        const meta = {
+            url: search,
+            keyword: header.request.query
+        };
+        if (result && result.length) {
+            result.forEach(row => {
+                const rowAsDefault = row.default === true;
+                const rowHits = row.hits;
+                if (rowHits && rowHits.length) {
+                    rowHits.forEach((rowHit, hitIdx) => {
+                        suggestions.push({
+                            label: rowHit.cmd,
+                            value: rowHit,
+                            highlighted: rowAsDefault && hitIdx === 0,
+                            meta
+                        });
+                        const relations = rowHit.relations;
+                        if (relations) {
+                            Object.keys(relations).forEach(key => {
+                                const relation = relations[key];
+                                const relationAsDefault = relation.default === true;
+                                const relationHits = relation.hits;
+                                if (relationHits && relationHits.length) {
+                                    relationHits.forEach((relationHit, relationHitIdx) => {
+                                        suggestions.push({
+                                            label: relationHit.cmd,
+                                            value: relationHit,
+                                            parent: rowHit,
+                                            asSub: true,
+                                            highlighted: relationAsDefault && relationHitIdx === 0,
+                                            meta
+                                        });
+                                    });
+                                }
+                            });
+                        }
+                    });
+                }
+            });
+        }
+        return {
+            header,
+            meta,
+            suggestions,
+            action,
+            searchUrl: search
+        };
+    };
+    autoSuggestElem.addEventListener("suggestions-fetch-requested", suggest);
+    function suggest(ev) {
+        // Stop default data fetching
+
+        ev.preventDefault();
+
+        // construct cache key off the query object
+        var cacheKey = JSON.stringify(ev.detail.query);
+
+        // (optional) use util to parse response
+        var responseData = {
+            "header": {
+                "request": {
+                    "filter": "",
+                    "highlight": true,
+                    "userProfileAssetClass": "CSH",
+                    "api-key": "czZTQ5MjY4",
+                    "eikon_version": "Eikon Web",
+                    "profile": "AlertsUI2",
+                    "query": "IBV",
+                    "uuid": "PATESTCPA724",
+                    "appl_category": []
+                },
+                "response": {
+                    "duration": 57,
+                    "server": "c962fkkaswb04.int.thomsonreuters.com",
+                    "num_results": 10
+                }
+            },
+            "result": [
+                {
+                    "name": "Equities",
+                    "hits": [
+                        {
+                            "score": 6867489,
+                            "navigation": null,
+                            "id": "1097326",
+                            "title": "International Business Vehicle Corp",
+                            "subtitle": "Ordinary Share - NYSE Consolidated - IBV",
+                            "symbol": "" + "<b>" + ev.detail.query + "</b>" + "",
+                            "cmd": "IBV",
+                            "relations": {},
+                            "position": 0,
+                            "source": "12",
+                            "explanation": null,
+                            "p": {
+                                "RIC": "IBV",
+                                "IsChain": false,
+                                "PermID": "55839165994",
+                                "OAPermID": "4295904307"
+                            },
+                            "ac": [
+                                "A:1",
+                                "A:1L"
+                            ],
+                            "s": "IBV",
+                            "vc": "EQ",
+                            "fr": false,
+                            "st": "RIC",
+                            "preview": true
+                        },
+                        {
+                            "score": 2762007,
+                            "navigation": null,
+                            "id": "131770829",
+                            "title": "International Business Vehicle Corp",
+                            "subtitle": "Ordinary Share - MiFID Composite Cross Market Service - IBV",
+                            "symbol": "" + "<b>" + ev.detail.query + "</b>" + "IUSD.xbo",
+                            "cmd": "IBVIUSD.xbo",
+                            "relations": {},
+                            "position": 1,
+                            "source": "12",
+                            "explanation": null,
+                            "p": {
+                                "RIC": "IBVIUSD.xbo",
+                                "IsChain": false,
+                                "PermID": "21523029548",
+                                "OAPermID": "4295904307"
+                            },
+                            "ac": [
+                                "A:1",
+                                "A:1L"
+                            ],
+                            "s": "IBVIUSD.xbo",
+                            "vc": "EQ",
+                            "fr": false,
+                            "st": "RIC",
+                            "preview": true
+                        }
+                    ],
+                    "hasMore": true,
+                    "default": false,
+                    "size": 2,
+                    "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllEquities&Search.Value=ibV"
+                },
+                {
+                    "name": "Funds",
+                    "hits": [
+                        {
+                            "score": 2741047,
+                            "navigation": null,
+                            "id": "298223588",
+                            "title": "iShares iBonds Dec 2024 Term Muni Bond ETF",
+                            "subtitle": "Bond ETF - US123712312 - USD - Cboe Consolidated - IBVM",
+                            "symbol": "" + "<b>" + ev.detail.query + "</b>" + "M.K",
+                            "cmd": "IBVM.K",
+                            "relations": {},
+                            "position": 4,
+                            "source": "24",
+                            "explanation": null,
+                            "p": {
+                                "RIC": "IBVM.K",
+                                "IsChain": false,
+                                "PermID": "21642135445",
+                                "lipperId": "40215430"
+                            },
+                            "ac": [
+                                "A:5",
+                                "A:2X",
+                                "A:L0",
+                                "A:7",
+                                "A:GL"
+                            ],
+                            "s": "IBVM.K",
+                            "vc": "FND",
+                            "fr": false,
+                            "st": "RIC",
+                            "preview": true
+                        }
+                    ],
+                    "hasMore": true,
+                    "default": false,
+                    "size": 1,
+                    "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllFunds&Search.Value=ibV"
+                },
+                {
+                    "name": "Options",
+                    "hits": [
+                        {
+                            "score": 2157436,
+                            "navigation": null,
+                            "id": "585064349",
+                            "title": "OPRA International Business Vehicle Equity Option 145 Call Oct 2022 - IBV",
+                            "subtitle": "Equity Cash Option - OPRA - IBVJ2122C145000",
+                            "symbol": "" + "<b>" + ev.detail.query + "</b>" + "J212214500.U",
+                            "cmd": "IBVJ212214500.U",
+                            "relations": {},
+                            "position": 5,
+                            "source": "14",
+                            "explanation": null,
+                            "p": {
+                                "RIC": "IBVJ212214500.U",
+                                "IsChain": false,
+                                "PermID": "21873654768"
+                            },
+                            "ac": [
+                                "A:1",
+                                "A:2K",
+                                "A:1T",
+                                "A:7",
+                                "A:G1",
+                                "A:60"
+                            ],
+                            "s": "IBVJ212214500.U",
+                            "vc": "OPT",
+                            "fr": false,
+                            "st": "RIC",
+                            "preview": false
+                        }
+                    ],
+                    "hasMore": true,
+                    "default": false,
+                    "size": 1,
+                    "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllOptions&Search.Value=ibV"
+                },
+                {
+                    "name": "Indices",
+                    "hits": [
+                        {
+                            "score": 2157150,
+                            "navigation": null,
+                            "id": "215781470",
+                            "title": "INTL BUSINES Single Stock Dividend",
+                            "subtitle": "Equity Index",
+                            "symbol": "0#.IBVDIV",
+                            "cmd": "0#.IBVDIV",
+                            "relations": {},
+                            "position": 6,
+                            "source": "7",
+                            "explanation": null,
+                            "p": {
+                                "RIC": "0#.IBVDIV",
+                                "OAPermID": "4298427948"
+                            },
+                            "ac": [
+                                "M:D6",
+                                "I:M",
+                                "I:17",
+                                "A:1"
+                            ],
+                            "s": "0#.IBVDIV",
+                            "vc": "INDX",
+                            "fr": false,
+                            "st": "RIC",
+                            "preview": true
+                        }
+                    ],
+                    "hasMore": true,
+                    "default": false,
+                    "size": 1,
+                    "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllIndices&Search.Value=ibV"
+                },
+                {
+                    "name": "Commodities",
+                    "hits": [
+                        {
+                            "score": 1598945,
+                            "navigation": null,
+                            "id": "606788540",
+                            "title": "Argus Ice Brent Month 2 Snapshot PA5000637",
+                            "subtitle": "Crude Oil - Commodity Spot - ARGUS",
+                            "symbol": "" + "<b>" + ev.detail.query + "</b>" + "SST=ARG",
+                            "cmd": "IBVSST=ARG",
+                            "relations": {},
+                            "position": 7,
+                            "source": "15",
+                            "explanation": null,
+                            "p": {
+                                "RIC": "IBVSST=ARG",
+                                "IsChain": false,
+                                "PermID": "21891574387"
+                            },
+                            "ac": [
+                                "A:4",
+                                "A:1Q"
+                            ],
+                            "s": "IBVSST=ARG",
+                            "vc": "COM",
+                            "fr": false,
+                            "st": "RIC",
+                            "preview": true
+                        }
+                    ],
+                    "hasMore": true,
+                    "default": false,
+                    "size": 1,
+                    "moreLink": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV"
+                },
+                {
+                    "name": "Fixed Income",
+                    "hits": [
+                        {
+                            "score": 1465259,
+                            "navigation": null,
+                            "id": "0x00102c80bf6b046c",
+                            "title": "International Business Vehicle Corp - " + "<b>" + ev.detail.query + "</b>" + " 2.875% 09-Nov-2022",
+                            "subtitle": "Plain Vanilla Fixed Coupon Bond - Underwritten",
+                            "symbol": "US459200JC60",
+                            "cmd": "US459200JC60",
+                            "relations": {},
+                            "position": 8,
+                            "source": "3",
+                            "explanation": null,
+                            "p": {
+                                "RIC": "459200JC6=",
+                                "OAPermID": "4295904307"
+                            },
+                            "ac": [
+                                "A:2",
+                                "A:J"
+                            ],
+                            "s": "459200JC6=",
+                            "vc": "BOND",
+                            "fr": false,
+                            "st": "RIC",
+                            "preview": true
+                        }
+                    ],
+                    "hasMore": true,
+                    "default": false,
+                    "size": 1,
+                    "moreLink": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV"
+                },
+                {
+                    "name": "FX",
+                    "hits": [
+                        {
+                            "score": 237124,
+                            "navigation": null,
+                            "id": "47051538460",
+                            "title": "US Dollar/Chinese Renminbi 6 Month FX Forecast",
+                            "subtitle": "IBV INDIA - 6 Month",
+                            "symbol": "CNY6MP=0631",
+                            "cmd": "CNY6MP=0631",
+                            "relations": {},
+                            "position": 9,
+                            "source": "23",
+                            "explanation": null,
+                            "p": {
+                                "RIC": "CNY6MP=0631",
+                                "PermID": "47051538460"
+                            },
+                            "ac": [
+                                "M:D6",
+                                "A:55",
+                                "A:3",
+                                "A:9",
+                                "M:1MN"
+                            ],
+                            "s": "CNY6MP=0631",
+                            "vc": "FX",
+                            "fr": false,
+                            "st": "RIC",
+                            "preview": false
+                        }
+                    ],
+                    "hasMore": true,
+                    "default": false,
+                    "size": 1,
+                    "moreLink": "cpurl://views.cp./Explorer/SRCHxALL.aspx?vcn=SearchAllFXMoney&Search.Value=ibV"
+                }
+            ],
+            "search": "cpurl://apps.cp./apps/SearchAll?Search.Value=ibV",
+            "action": "\"IBV\" SRCH",
+            "assetClassifierStatus": "NOT_INVOKED",
+            "assetClassifierExplanation": "Current profile is not in the list of the silent mode profiles for asset classifier."
+        };
+        var parsed = flattenResponse(responseData);
+
+        // cache the response
+        autoSuggestElem.cacheModel.set(cacheKey, parsed);
+
+        // set suggestions data
+        autoSuggestElem.setSuggestions(parsed);
+    }
+}
+
+// ========== End mock data server section  ======================================
+
 
-
-

Note: you can use the listen method to listen to a custom event fired from Grid and Grid's plugins, instead of the conventional addEventListener method.

-
+




diff --git a/template-93.html b/template-93.html index cda7928b..3ad5af4b 100644 --- a/template-93.html +++ b/template-93.html @@ -1,110 +1,37 @@ -

Custom Tooltip

-

A custom tooltip allows users to customize tooltips within the grid, enabling them to render elements and incorporate them into the tooltip.

-

Multiple lines tooltip

-

Sometimes, the application needs to use tooltips with multiple lines to enhance user understanding. In the example below, we demonstrate how to show multiple lines for a custom tooltip below.

-
efx-grid {
-    height: 300px;
-    margin-bottom: 40px;
-}
-
-
<efx-grid id="grid"></efx-grid>
-<ef-tooltip id="my_tooltip"></ef-tooltip>
-    <div style="display: none;">
-            <div id="container_custom_tooltip">
-                <div class="line1"></div>
-                <div class="line2"></div>
-                <div class="line3"></div>
-        </div>
-    </div>
+

Using Core APIs

+

Core Grid is the internal part of Grid, containing logics for UI and layout manipulation. Grid is just a wrapper that make the JavaScript grid component (Core Grid) become a custom element in the Web Components standard.

+

Some of the APIs are already propagated and exposed to the api property of the element. However, most of the APIs are still only available in the core part of Grid.

+

To unlock all the APIs you need to get a reference to the Core Grid by using the getCoreGrid method from api as shown in the below sample:

+
var grid = document.getElementsByTagName("efx-grid")[0];
+grid.addEventListener("configured", function(e) {
+    var core = e.detail.api.getCoreGrid(); // Getting Core Grid reference
+    
+    var titleSection = core.getSection("title");
+    var contentSection = core.getSection("content");
+    var colCount = core.getColumnCount();
+});
 
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-
-var fields = ["companyName", "industry", "market", "CF_LAST", "PCTCHNG"];
-var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 10 });
-var configObj = {
-    columns: [
-        { name: "Multiple Lines Tooltip", field: fields[0], },
-        { name: "Normal Tooltip", field: fields[1], binding: customBinding },
-        { name: "No Tooltip", field: fields[2] },
-    ],
-    staticDataRows: records
-};
-const CUSTOM_TOOLTIP_FIELD = fields[0];
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-var tooltip = document.getElementById("my_tooltip");
-tooltip.condition = customTooltipCondition; // Set condition that tooltip should be rendered
-tooltip.renderer = customTooltipRenderer; // Set what will be rendered in tooltip
-
-function customBinding(e) {
-    var cell = e.cell;
-    var field = e.field;
-    var data = e.rowData[field];
-    cell.setTooltip(data);
-    cell.setContent(data);
+
+

Note: The custom elements are not defined immediately after the page load. api will only be available after the element is defined. So, use the configured event to ensure the existence of the api property.

+
+

For all available Core Grid APIs, see this page.

+

Getting built-in plugins and extensions

+

Due to the long history of its development, Grid contains a lot of legacy codes, including built-in plugins. A plugin is just an old name for an extension. So, to get a reference for plugins or extensions, you can use the getPlugin method from the Core Grid.

+
+

Note: The "SortableTitlePlugin" is the only notable plugin worth mentioning among built-in plugins, since it manages how Grid sorts the data.

+
+

The following example shows how you can listen to the columnSorted event fired after each sorting state change from the SortableTitlePlugin.

+

Example

+
efx-grid {
+    height: 200px;
 }
-
-function customTooltipCondition(target, paths) {
-    var relPos = grid.api.getRelativePosition(target);
-    var colIndex = relPos.colIndex;
-    var field = grid.api.getColumnField(colIndex);
-
-    if (relPos.hit && field == CUSTOM_TOOLTIP_FIELD) {
-        return true;
-    }
-    return false;
-}
-
-function customTooltipRenderer(target) {
-    var relPos = grid.api.getRelativePosition(target);
-    if (relPos.sectionType != "title") {
-        var rowIndex = relPos.rowIndex;
-        var rowDef = grid.api.getRowDefinition(rowIndex);
-        if (!rowDef) {
-            return null;
-        }
-        var rowData = rowDef.getRowData();
-        let container = document.getElementById("container_custom_tooltip");
-        container.querySelector(".line1").textContent = rowData["companyName"];
-        container.querySelector(".line2").textContent = rowData["market"];
-        container.querySelector(".line3").textContent = rowData["industry"];
-        return container;
-    }
-    return null
-}
-
-

Tooltip with complex element

-

To create the tooltip exactly as you desire, simply create a special element and then add details with grid information inside. This feature allows you to customize the tooltip to suit your needs perfectly, aligning seamlessly with your current project. Follow the example below for guidance.

-
efx-grid {
-    height: 300px;
-    margin-bottom: 40px;
+html hr {
+    margin: 5px;
 }
 
-
<efx-grid id="grid"></efx-grid>
-<ef-tooltip id="my_tooltip"></ef-tooltip>
-<div style="display: none;">
-    <div id="container_custom_tooltip">
-        <div style="font-weight: bold;">
-            <span class="company-name"></span><span> (</span><span class="market"></span><span>)</span>
-        </div>
-        <hr style="margin: 0px;">
-        <div style="color: red;" class="price-color">
-            <span>£</span><span class="cf-last"></span>
-            <span>(</span><span class="pctchng">
-            </span><span>%)</span>
-            <ef-pill class="row-index"></ef-pill>
-        </div>
-    </div>
-</div>
+
<big id="msg_div">Click grid top section to sort</big>
+<hr>
+<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -115,74 +42,36 @@ 

Multiple lines tooltip

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { numRows: 6 }); + +var onColumnSorted = function(e) { + msg_div.textContent = "Column " + e.colIndex + " is sorted in " + (e.sortOrder === "a" ? "ascending" : "descending") + " order"; +}; -var fields = ["companyName", "industry", "market", "CF_LAST", "PCTCHNG"]; -var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 10 }); var configObj = { - rowVirtualization: false, + sorting: { + sortableColumns: true, + }, columns: [ - { name: "Tooltip with Complex Element", field: fields[0], }, - { name: "Normal Tooltip", field: fields[1], binding: customBinding }, - { name: "No Tooltip", field: fields[2] }, + {name: "Company", field: fields[0]}, + {name: "Market", field: fields[1], width: 120}, + {name: "Last", field: fields[2], width: 100}, + {name: "Net. Chng", field: fields[3], width: 100}, + {name: "Industry", field: fields[4]} ], staticDataRows: records }; -const COMPLEXT_TOOLTIP_FIELD = fields[0]; - var grid = document.getElementById("grid"); +grid.addEventListener("configured", function(e) { + var core = e.detail.api.getCoreGrid(); + + var plugin = core.getPlugin("SortableTitle"); + plugin.listen("columnSorted", onColumnSorted); +}); grid.config = configObj; - -var tooltip = document.getElementById("my_tooltip"); -tooltip.condition = customTooltipCondition; // Set condition that tooltip should be rendered -tooltip.renderer = customTooltipRenderer; // Set what will be rendered in tooltip - -function customBinding(e) { - var cell = e.cell; - var field = e.field; - var data = e.rowData[field]; - cell.setTooltip(data); - cell.setContent(data); -} - -function customTooltipCondition(target, paths) { - var relPos = grid.api.getRelativePosition(target); - var colIndex = relPos.colIndex; - var field = grid.api.getColumnField(colIndex); - if (relPos.hit && field == COMPLEXT_TOOLTIP_FIELD) { - return true; - } - return false; -} - -function customTooltipRenderer(target) { - var relPos = grid.api.getRelativePosition(target); - if (relPos.sectionType != "title") { - var rowIndex = relPos.rowIndex; - var rowDef = grid.api.getRowDefinition(rowIndex); - if (!rowDef) { - return null; - } - var rowData = rowDef.getRowData(); - var market = rowData["market"]; - var companyName = rowData["companyName"]; - var lastPrice = rowData["CF_LAST"]; - var priceChange = rowData["PCTCHNG"]; - // Assign only value element inside container element - var container = document.getElementById("container_custom_tooltip"); - container.querySelector(".market").textContent = market; - container.querySelector(".company-name").textContent = companyName; - container.querySelector(".cf-last").textContent = lastPrice; - container.querySelector(".pctchng").textContent = priceChange; - if (priceChange < 0) { - container.querySelector(".price-color").style.color = "red"; - } else { - container.querySelector(".price-color").style.color = "green"; - } - container.querySelector(".row-index").textContent = rowIndex; - return container; - } - return null; -}
-




+
+

Note: you can use the listen method to listen to a custom event fired from Grid and Grid's plugins, instead of the conventional addEventListener method.

+
diff --git a/template-94.html b/template-94.html index 8d35fd26..cda7928b 100644 --- a/template-94.html +++ b/template-94.html @@ -1,14 +1,21 @@ -

Handling 50,000 Rows

-

Grid utilizes a virtual rendering technique that renders a range of visible rows and uses/shares the same cells across multiple rows. This allows you to display an extraordinarily large number of rows on the grid, as shown in the example below.

-
-

Note that by default, the grid's wheel scrolling behavior will skip multiple rows based on the total number of rows, to avoid small and tiresome scrolling. Use the linearWheelScrolling flag to enable native wheel scrolling behavior.

-
-

Example

-
efx-grid {
-    height: 500px;
+

Custom Tooltip

+

A custom tooltip allows users to customize tooltips within the grid, enabling them to render elements and incorporate them into the tooltip.

+

Multiple lines tooltip

+

Sometimes, the application needs to use tooltips with multiple lines to enhance user understanding. In the example below, we demonstrate how to show multiple lines for a custom tooltip below.

+
efx-grid {
+    height: 300px;
+    margin-bottom: 40px;
 }
 
<efx-grid id="grid"></efx-grid>
+<ef-tooltip id="my_tooltip"></ef-tooltip>
+    <div style="display: none;">
+            <div id="container_custom_tooltip">
+                <div class="line1"></div>
+                <div class="line2"></div>
+                <div class="line3"></div>
+        </div>
+    </div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -19,38 +26,163 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -DataGenerator.addFieldInfo("rowNumber", { - type: "function", - generate: function(info, seed) { - return ++info.count; - }, - count: 0, -}); -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "rowNumber"]; -var records = DataGenerator.generateRecords(fields, { numRows: 50000 }); + +var fields = ["companyName", "industry", "market", "CF_LAST", "PCTCHNG"]; +var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 10 }); var configObj = { - linearWheelScrolling: true, columns: [ - {name: "ID", field: fields[5], alignment: "center", width: 80}, - {name: "Company", field: fields[0]}, - { - name: "Market", - field: fields[1], - width: 120, - binding: TextFormatter.create({ - styles: { - "backgroundColor": "rgba(120, 120, 220, 0.3)" - } - }) - }, - {name: "Last", field: fields[2], width: 100}, - {name: "Net. Chng", field: fields[3], width: 100}, - {name: "Industry", field: fields[4]} + { name: "Multiple Lines Tooltip", field: fields[0], }, + { name: "Normal Tooltip", field: fields[1], binding: customBinding }, + { name: "No Tooltip", field: fields[2] }, ], staticDataRows: records }; +const CUSTOM_TOOLTIP_FIELD = fields[0]; var grid = document.getElementById("grid"); grid.config = configObj; +var tooltip = document.getElementById("my_tooltip"); +tooltip.condition = customTooltipCondition; // Set condition that tooltip should be rendered +tooltip.renderer = customTooltipRenderer; // Set what will be rendered in tooltip + +function customBinding(e) { + var cell = e.cell; + var field = e.field; + var data = e.rowData[field]; + cell.setTooltip(data); + cell.setContent(data); +} + +function customTooltipCondition(target, paths) { + var relPos = grid.api.getRelativePosition(target); + var colIndex = relPos.colIndex; + var field = grid.api.getColumnField(colIndex); + + if (relPos.hit && field == CUSTOM_TOOLTIP_FIELD) { + return true; + } + return false; +} + +function customTooltipRenderer(target) { + var relPos = grid.api.getRelativePosition(target); + if (relPos.sectionType != "title") { + var rowIndex = relPos.rowIndex; + var rowDef = grid.api.getRowDefinition(rowIndex); + if (!rowDef) { + return null; + } + var rowData = rowDef.getRowData(); + let container = document.getElementById("container_custom_tooltip"); + container.querySelector(".line1").textContent = rowData["companyName"]; + container.querySelector(".line2").textContent = rowData["market"]; + container.querySelector(".line3").textContent = rowData["industry"]; + return container; + } + return null +} +
+

Tooltip with complex element

+

To create the tooltip exactly as you desire, simply create a special element and then add details with grid information inside. This feature allows you to customize the tooltip to suit your needs perfectly, aligning seamlessly with your current project. Follow the example below for guidance.

+
efx-grid {
+    height: 300px;
+    margin-bottom: 40px;
+}
+
+
<efx-grid id="grid"></efx-grid>
+<ef-tooltip id="my_tooltip"></ef-tooltip>
+<div style="display: none;">
+    <div id="container_custom_tooltip">
+        <div style="font-weight: bold;">
+            <span class="company-name"></span><span> (</span><span class="market"></span><span>)</span>
+        </div>
+        <hr style="margin: 0px;">
+        <div style="color: red;" class="price-color">
+            <span>£</span><span class="cf-last"></span>
+            <span>(</span><span class="pctchng">
+            </span><span>%)</span>
+            <ef-pill class="row-index"></ef-pill>
+        </div>
+    </div>
+</div>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+
+var fields = ["companyName", "industry", "market", "CF_LAST", "PCTCHNG"];
+var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 10 });
+var configObj = {
+    rowVirtualization: false,
+    columns: [
+        { name: "Tooltip with Complex Element", field: fields[0], },
+        { name: "Normal Tooltip", field: fields[1], binding: customBinding },
+        { name: "No Tooltip", field: fields[2] },
+    ],
+    staticDataRows: records
+};
+const COMPLEXT_TOOLTIP_FIELD = fields[0];
+
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+var tooltip = document.getElementById("my_tooltip");
+tooltip.condition = customTooltipCondition; // Set condition that tooltip should be rendered
+tooltip.renderer = customTooltipRenderer; // Set what will be rendered in tooltip
+
+function customBinding(e) {
+    var cell = e.cell;
+    var field = e.field;
+    var data = e.rowData[field];
+    cell.setTooltip(data);
+    cell.setContent(data);
+}
+
+function customTooltipCondition(target, paths) {
+    var relPos = grid.api.getRelativePosition(target);
+    var colIndex = relPos.colIndex;
+    var field = grid.api.getColumnField(colIndex);
+    if (relPos.hit && field == COMPLEXT_TOOLTIP_FIELD) {
+        return true;
+    }
+    return false;
+}
+
+function customTooltipRenderer(target) {
+    var relPos = grid.api.getRelativePosition(target);
+    if (relPos.sectionType != "title") {
+        var rowIndex = relPos.rowIndex;
+        var rowDef = grid.api.getRowDefinition(rowIndex);
+        if (!rowDef) {
+            return null;
+        }
+        var rowData = rowDef.getRowData();
+        var market = rowData["market"];
+        var companyName = rowData["companyName"];
+        var lastPrice = rowData["CF_LAST"];
+        var priceChange = rowData["PCTCHNG"];
+        // Assign only value element inside container element
+        var container = document.getElementById("container_custom_tooltip");
+        container.querySelector(".market").textContent = market;
+        container.querySelector(".company-name").textContent = companyName;
+        container.querySelector(".cf-last").textContent = lastPrice;
+        container.querySelector(".pctchng").textContent = priceChange;
+        if (priceChange < 0) {
+            container.querySelector(".price-color").style.color = "red";
+        } else {
+            container.querySelector(".price-color").style.color = "green";
+        }
+        container.querySelector(".row-index").textContent = rowIndex;
+        return container;
+    }
+    return null;
+}
 
-
\ No newline at end of file +




diff --git a/template-95.html b/template-95.html index 6728f035..8d35fd26 100644 --- a/template-95.html +++ b/template-95.html @@ -1,27 +1,14 @@ -

Keyboard inputs

-

Native tab navigation

-

Grid element is focusable which allows it to receive keyboard inputs. Thus, Grid supports tab navigation from and to another focusable elements. The example below illustrates how Tab and Shift+Tab keys shift the focus between elements.

-

Native tab navigation example

-
efx-grid {
-    height: 200px;
-}
-html hr {
-    margin: 5px;
-}
-mark {
-    opacity: 0;
-    padding: 2px;
-    transition: opacity 0.2s ease-in;
+

Handling 50,000 Rows

+

Grid utilizes a virtual rendering technique that renders a range of visible rows and uses/shares the same cells across multiple rows. This allows you to display an extraordinarily large number of rows on the grid, as shown in the example below.

+
+

Note that by default, the grid's wheel scrolling behavior will skip multiple rows based on the total number of rows, to avoid small and tiresome scrolling. Use the linearWheelScrolling flag to enable native wheel scrolling behavior.

+
+

Example

+
efx-grid {
+    height: 500px;
 }
 
-
<input id="dummy_in1" value="input 1">
-<input id="dummy_in2" value="input 2">
-<mark id="key_indi">Tab key</mark>
-<hr>
-<efx-grid id="grid"></efx-grid>
-<hr>
-<input id="dummy_in3" value="input 3">
-<input id="dummy_in4" value="input 4">
+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -32,117 +19,32 @@ 

Native tab navigation example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { numRows: 5 }); - -var configObj = { - columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], width: 120}, - {name: "Last", field: fields[2], width: 100}, - {name: "Net. Chng", field: fields[3], width: 100}, - {name: "Industry", field: fields[4]} - ], - staticDataRows: records -}; - -var grid = document.getElementById("grid"); -grid.config = configObj; - -window.addEventListener("keydown", function onKeyDown(e) { - if(e.keyCode === 9) { - key_indi.style.opacity = "1"; - setTimeout(onHideKeyIndicator, 400); - } +DataGenerator.addFieldInfo("rowNumber", { + type: "function", + generate: function(info, seed) { + return ++info.count; + }, + count: 0, }); -function onHideKeyIndicator() { - key_indi.style.opacity = ""; -} -
-

Tab navigation with Grid's content

-

Since Grid utilizes row virtualization, not all Grid's content are rendered in the document. Thus, tab navigation needs to be managed by Grid. To enable tab navigation for Grid's content, set tabToFocus property to true on Grid configuration object and set focusable property to true on each column with focusable content, as shown on the following code snippet.

-
var configObj = {
-    tabToFocus: true,
-    columns: [
-        {field: "column1", focusable: true},
-        {field: "column2"},
-        {field: "column3", focusable: true},
-    ]
-};
-
-

Tab navigation with single focusable element example

-
efx-grid {
-    height: 220px;
-}
-html hr {
-    margin: 5px;
-}
-mark {
-    opacity: 0;
-    padding: 2px;
-    transition: opacity 0.2s ease-in;
-}
-
-
<input id="dummy_in1" value="input 1">
-<input id="dummy_in2" value="input 2">
-<mark id="key_indi">Tab key</mark>
-<hr>
-<efx-grid id="grid"></efx-grid>
-<hr>
-<input id="dummy_in3" value="input 3">
-<input id="dummy_in4" value="input 4">
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var records = DataGenerator.generateRecords(fields, { numRows: 20 });
-
-function onDropdownBinding(e) {
-    var cell = e.cell;
-    var content = cell.getContent();
-    if(!content || !content._myDropdown) {
-        content = document.createElement("select");
-        content._myDropdown = true;
-        for(var i = 0; i < 3; ++i) {
-            var opt = document.createElement("option");
-            opt.value = i;
-            opt.textContent = "Item " + (i + 1);
-            content.appendChild(opt);
-        }
-    }
-    cell.setContent(content);
-}
-function onInputBinding(e) {
-    var cell = e.cell;
-    var content = cell.getContent();
-    if(!content || !content._myInput) {
-        content = document.createElement("input");
-        content._myInput = true;
-    }
-    content.value = e.data;
-    cell.setContent(content);
-}
-
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "rowNumber"];
+var records = DataGenerator.generateRecords(fields, { numRows: 50000 });
 var configObj = {
-    tabToFocus: true,
+    linearWheelScrolling: true,
     columns: [
+        {name: "ID", field: fields[5], alignment: "center", width: 80},
         {name: "Company", field: fields[0]},
         {
-            name: "Market", field: fields[1], width: 120, 
-            binding: onInputBinding, focusable: true
+            name: "Market", 
+            field: fields[1], 
+            width: 120, 
+            binding: TextFormatter.create({
+                styles: {
+                    "backgroundColor": "rgba(120, 120, 220, 0.3)"
+                }
+            })
         },
         {name: "Last", field: fields[2], width: 100},
-        {
-            name: "Dropdown", width: 100, 
-            binding: onDropdownBinding, focusable: true
-        },
+        {name: "Net. Chng", field: fields[3], width: 100},
         {name: "Industry", field: fields[4]}
     ],
     staticDataRows: records
@@ -150,257 +52,5 @@ 

Tab navigation wit var grid = document.getElementById("grid"); grid.config = configObj; - -window.addEventListener("keydown", function onKeyDown(e) { - if(e.keyCode === 9) { - key_indi.style.opacity = "1"; - setTimeout(onHideKeyIndicator, 400); - } -}); -function onHideKeyIndicator() { - key_indi.style.opacity = ""; -} -

-

Tab navigation with custom content example

-

When you have a custom content in the cell, you will need to tell Grid which element is to be focused by specifying nextFocusableElement property on the event argument in tabNavigation event. You can use tabNavigation event to manage order of focusable element in case of you have multiple focusable elements in a single cell.

-
efx-grid {
-    height: 220px;
-}
-html hr {
-    margin: 5px;
-}
-mark {
-    opacity: 0;
-    padding: 2px;
-    transition: opacity 0.2s ease-in;
-}
-
-
<input id="dummy_in1" value="input 1">
-<input id="dummy_in2" value="input 2">
-<mark id="key_indi">Tab key</mark>
-<hr>
-<efx-grid id="grid"></efx-grid>
-<hr>
-<input id="dummy_in3" value="input 3">
-<input id="dummy_in4" value="input 4">
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-function buttonsBinding(e) {
-    var cell = e.cell;
-    var content = cell.getContent();
-    if(!content || !content._inputs) {
-        content = document.createElement("div");
-        content._inputs = true;
-        
-        var input1 = document.createElement("input");
-        var input2 = document.createElement("input");
-        input1.style.width = "30px";
-        input2.style.width = "30px";
-        input1.value = "A";
-        input2.value = "B";
-        content.appendChild(input1);
-        content.appendChild(input2);
-        content._tabIndices = [input1, input2];
-    }
-    cell.setContent(content);
-}
-
-function onTabNavigation(e) {
-    var activeElement = e.activeElement;
-    var content = e.cellContent;
-    
-    var at = content._tabIndices.indexOf(activeElement);
-    if(e.shiftKey) {
-        e.nextFocusableElement = content._tabIndices[(at >= 0) ? at - 1 : content._tabIndices.length  - 1];
-    } else {
-        e.nextFocusableElement = content._tabIndices[at + 1];
-    }
-}
-
-var fields = ["id", "companyName", "custom1", "custom2", "market", "industry"];
-var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 });
-var columns = fields.map(function(f, idx) {
-    return {
-        field: f
-    };
-});
-columns[0].width = 60;
-columns[1].width = 120;
-
-columns[2].width = 100;
-columns[3].width = 100;
-columns[2].focusable = true;
-columns[3].focusable = true;
-columns[2].binding = buttonsBinding;
-columns[3].binding = buttonsBinding;
-
-var configObj = {
-    tabToFocus: true,
-    defaultColumnOptions: {
-        notRealTimeField: true,
-        textAlign: "c"
-    },
-    columns: columns,
-    tabNavigation: onTabNavigation,
-    staticDataRows: records
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-
-window.addEventListener("keydown", function onKeyDown(e) {
-    if(e.keyCode === 9) {
-        key_indi.style.opacity = "1";
-        setTimeout(onHideKeyIndicator, 400);
-    }
-});
-function onHideKeyIndicator() {
-    key_indi.style.opacity = "";
-}
-
-

Copy and paste operations

-

Although Grid can get focus through Tab key, it does not get focus through mouse click by default. This is to allow mouse interaction with its content by not automatically shifting focus on Grid element (e.g., text selection requires focus to stay on the same element). If Grid does not contain any interactive content, you can listening to click event and put focus on the grid. To put the focus on Grid element, use focus() method from Grid's APIs.

-

Once Grid is in focus, you can catch native copy and paste events from Grid to manipulate or retrieve data from system clipboard. The example below shows how to populate data on Grid using clipboard data and setting Grid data to the clipboard.

-

Copying and pasting grid's content in TSV format example

-
html body {
-    padding: 5px;
-    box-sizing: border-box;
-}
-html hr {
-    margin: 5px;
-}
-efx-grid {
-    height: 200px;
-}
-efx-grid:focus-within {
-    outline-width: 1px;
-    outline-style: solid;
-    outline-color: blue;
-}
-mark {
-    opacity: 0;
-    padding: 4px;
-    transition: opacity 0.5s ease-out;
-}
-textarea {
-    width: 100%;
-    height: 120px;
-}
-
-
<big>Try copying texts below and pasting them onto grid.</big>
-<hr>
-<textarea id="msg_ta"></textarea>
-<hr>
-<big>Try clicking grid and copying (<b>Ctrl/Command + C</b>) grid's content.</big>
-<br>
-<big>Then, paste the content on some other places.</big>
-<hr>
-<efx-grid id="grid"></efx-grid>
-<hr>
-<mark id="key_indi"></mark>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
-var dataset1 = DataGenerator.generateRecords(fields, { seed: 0, numRows: 4 });
-var dataset2 = DataGenerator.generateRecords(fields, { seed: 20, numRows: 7 });
-
-msg_ta.value = recordsToTSV(dataset2);
-msg_ta.addEventListener("focus", function(e) {
-    e.currentTarget.select();
-});
-
-var configObj = {
-    columns: [
-        {name: "Company", field: fields[0]},
-        {name: "Market", field: fields[1], width: 120},
-        {name: "Last", field: fields[2], width: 100},
-        {name: "Net. Chng", field: fields[3], width: 100},
-        {name: "Industry", field: fields[4]}
-    ]
-};
-
-var grid = document.getElementById("grid");
-grid.config = configObj;
-grid.data = dataset1;
-
-grid.addEventListener("click", function onClick(e) {
-    grid.api.focus();
-});
-grid.addEventListener("copy", function onCopy(e) {
-    var columnNames = grid.api.getColumnNames();
-    var rows = grid.api.getMultipleRowData(); // Get all row data from existing view
-    
-    // Build text in TSV format 
-    var text = columnNames.join("\t") + "\n" +
-        rows.map(recordToTSV).join("\n");
-    
-    e.clipboardData.setData("text/plain", text);
-    e.preventDefault();
-    
-    showKeyIndicator("Data is copied to clipboard");
-});
-grid.addEventListener("paste", function onPaste(e) {
-    e.preventDefault();
-    
-    var tsv = e.clipboardData.getData("text/plain");
-    grid.data = tsvToRecords(tsv);
-    
-    showKeyIndicator("Data is pasted onto Grid");
-});
-
-function recordToTSV(record) {
-    return ([
-        record[fields[0]],
-        record[fields[1]],
-        record[fields[2]],
-        record[fields[3]],
-        record[fields[4]]
-    ]).join("\t"); // TSV (Tab Separated Values)
-}
-function recordsToTSV(records) {
-    return records.map(recordToTSV).join("\n");
-}
-function tsvToRecords(tsv) {
-    if(!tsv) {
-        return [];
-    }
-    var lines = tsv.split("\n");
-    return lines.map(function(line) {
-        var obj = {};
-        line.split("\t").map(function(item, idx) {
-            var field = fields[idx] || "";
-            if(field) {
-                obj[field] = item;
-            }
-        });
-        return obj;
-    });
-}
-function showKeyIndicator(text) {
-    if(text) {
-        key_indi.textContent = text;
-    }
-    key_indi.style.opacity = "1";
-    setTimeout(onHideKeyIndicator, 1000);
-}
-function onHideKeyIndicator() {
-    key_indi.style.opacity = "";
-}
 
\ No newline at end of file diff --git a/template-96.html b/template-96.html index 91ba0644..06956e84 100644 --- a/template-96.html +++ b/template-96.html @@ -1,20 +1,27 @@ -

Loading Mask

-

Loading mask is not part of Grid. To follow the standard theme, the UI and functionalities are provided by loader component. So, you need to put an overlay on top of the grid and not inside of it. For more advanced UI and behaviors, the implementation has to be done on the application side.

-

Basic Example

-
#container_div {
-    position: relative; /*ef-loader has position absolute*/
-    height: 250px;
+

Keyboard inputs

+

Native tab navigation

+

Grid element is focusable which allows it to receive keyboard inputs. Thus, Grid supports tab navigation from and to another focusable elements. The example below illustrates how Tab and Shift+Tab keys shift the focus between elements.

+

Native tab navigation example

+
efx-grid {
+    height: 200px;
 }
-efx-grid {
-    height: 100%;
+html hr {
+    margin: 5px;
+}
+mark {
+    opacity: 0;
+    padding: 2px;
+    transition: opacity 0.2s ease-in;
 }
 
-
<button id="show_btn">Show Masking</button>
-<button id="hide_btn">Hide Masking</button>
-<br><br>
-<div id="container_div">
-    <efx-grid id="grid"></efx-grid>
-</div>
+
<input id="dummy_in1" value="input 1">
+<input id="dummy_in2" value="input 2">
+<mark id="key_indi">Tab key</mark>
+<hr>
+<efx-grid id="grid"></efx-grid>
+<hr>
+<input id="dummy_in3" value="input 3">
+<input id="dummy_in4" value="input 4">
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -25,20 +32,11 @@ 

Basic Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var loadingMaskEl = document.createElement("ef-loader"); // Element can be created at runtime +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { numRows: 5 }); -DataGenerator.addFieldInfo("rowNumber", { - type: "function", - generate: function(info, seed) { - return ++info.count; - }, - count: 0, -}); -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "rowNumber"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { columns: [ - {name: "ID", field: fields[5], alignment: "center", width: 80}, {name: "Company", field: fields[0]}, {name: "Market", field: fields[1], width: 120}, {name: "Last", field: fields[2], width: 100}, @@ -51,32 +49,48 @@

Basic Example

var grid = document.getElementById("grid"); grid.config = configObj; -document.getElementById("show_btn").addEventListener("click", function() { - document.getElementById("container_div").appendChild(loadingMaskEl); -}); - -document.getElementById("hide_btn").addEventListener("click", function() { - loadingMaskEl.remove(); +window.addEventListener("keydown", function onKeyDown(e) { + if(e.keyCode === 9) { + key_indi.style.opacity = "1"; + setTimeout(onHideKeyIndicator, 400); + } }); +function onHideKeyIndicator() { + key_indi.style.opacity = ""; +}
-

Infinite Scrolling with Data Fetching Example

-
efx-grid {
-    height: 250px;
+

Tab navigation with Grid's content

+

Since Grid utilizes row virtualization, not all Grid's content are rendered in the document. Thus, tab navigation needs to be managed by Grid. To enable tab navigation for Grid's content, set tabToFocus property to true on Grid configuration object and set focusable property to true on each column with focusable content, as shown on the following code snippet.

+
var configObj = {
+    tabToFocus: true,
+    columns: [
+        {field: "column1", focusable: true},
+        {field: "column2"},
+        {field: "column3", focusable: true},
+    ]
+};
+
+

Tab navigation with single focusable element example

+
efx-grid {
+    height: 220px;
 }
-.blur {
-    filter: blur(2px);
+html hr {
+    margin: 5px;
 }
-#container_div {
-    position: relative; /*ef-loader has position absolute*/
+mark {
+    opacity: 0;
+    padding: 2px;
+    transition: opacity 0.2s ease-in;
 }
 
-
<button id="fetch_btn">Fetch Data</button>
-<button id="clear_btn">Clear Data</button>
-<big>Total rows: <span id="total_row">0</span></big>
-<br>
-<div id="container_div">
-    <efx-grid id="grid"></efx-grid>
-</div>
+
<input id="dummy_in1" value="input 1">
+<input id="dummy_in2" value="input 2">
+<mark id="key_indi">Tab key</mark>
+<hr>
+<efx-grid id="grid"></efx-grid>
+<hr>
+<input id="dummy_in3" value="input 3">
+<input id="dummy_in4" value="input 4">
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -87,61 +101,232 @@ 

Basic Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var loading_mask = null; // Cache the element for re-using multiple times -DataGenerator.addFieldInfo("rowNumber", { - type: "function", - generate: function(info, seed) { - return ++info.count; - }, - count: 0, -}); -var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "rowNumber"]; +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { numRows: 20 }); -function fetchData() { // Simulate Data Fetching - if (!loading_mask) { // If we are not loading anything - toggleLoadingMask(); - setTimeout(onDataReceived, 1500); // Simulate delay for communication with a server +function onDropdownBinding(e) { + var cell = e.cell; + var content = cell.getContent(); + if(!content || !content._myDropdown) { + content = document.createElement("select"); + content._myDropdown = true; + for(var i = 0; i < 3; ++i) { + var opt = document.createElement("option"); + opt.value = i; + opt.textContent = "Item " + (i + 1); + content.appendChild(opt); + } } -}; + cell.setContent(content); +} +function onInputBinding(e) { + var cell = e.cell; + var content = cell.getContent(); + if(!content || !content._myInput) { + content = document.createElement("input"); + content._myInput = true; + } + content.value = e.data; + cell.setContent(content); +} -function clearData() { - grid.api.removeAllRows(); - document.getElementById("total_row").textContent = 0; +var configObj = { + tabToFocus: true, + columns: [ + {name: "Company", field: fields[0]}, + { + name: "Market", field: fields[1], width: 120, + binding: onInputBinding, focusable: true + }, + {name: "Last", field: fields[2], width: 100}, + { + name: "Dropdown", width: 100, + binding: onDropdownBinding, focusable: true + }, + {name: "Industry", field: fields[4]} + ], + staticDataRows: records }; -function onDataReceived() { - toggleLoadingMask(); // Remove loading mask - - var records = DataGenerator.generateRecords(fields, { numRows: 20 }); - grid.api.addStaticDataRows(records); - - document.getElementById("total_row").textContent = grid.api.getRowCount(); // Update UI -} +var grid = document.getElementById("grid"); +grid.config = configObj; -function onScrollEnd(e) { - var vScrollbar = grid.api.getCoreGrid().getVScrollbar(); - if (vScrollbar.isEndOfVerticalScroll()) { - fetchData(); +window.addEventListener("keydown", function onKeyDown(e) { + if(e.keyCode === 9) { + key_indi.style.opacity = "1"; + setTimeout(onHideKeyIndicator, 400); } +}); +function onHideKeyIndicator() { + key_indi.style.opacity = ""; +} +
+

Tab navigation with custom content example

+

When you have a custom content in the cell, you will need to tell Grid which element is to be focused by specifying nextFocusableElement property on the event argument in tabNavigation event. You can use tabNavigation event to manage order of focusable element in case of you have multiple focusable elements in a single cell.

+
efx-grid {
+    height: 220px;
 }
+html hr {
+    margin: 5px;
+}
+mark {
+    opacity: 0;
+    padding: 2px;
+    transition: opacity 0.2s ease-in;
+}
+
+
<input id="dummy_in1" value="input 1">
+<input id="dummy_in2" value="input 2">
+<mark id="key_indi">Tab key</mark>
+<hr>
+<efx-grid id="grid"></efx-grid>
+<hr>
+<input id="dummy_in3" value="input 3">
+<input id="dummy_in4" value="input 4">
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
 
-function toggleLoadingMask() {
-    if (loading_mask) {
-        grid.classList.remove("blur");
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+function buttonsBinding(e) {
+    var cell = e.cell;
+    var content = cell.getContent();
+    if(!content || !content._inputs) {
+        content = document.createElement("div");
+        content._inputs = true;
         
-        loading_mask.remove();
-        loading_mask = null;
+        var input1 = document.createElement("input");
+        var input2 = document.createElement("input");
+        input1.style.width = "30px";
+        input2.style.width = "30px";
+        input1.value = "A";
+        input2.value = "B";
+        content.appendChild(input1);
+        content.appendChild(input2);
+        content._tabIndices = [input1, input2];
+    }
+    cell.setContent(content);
+}
+
+function onTabNavigation(e) {
+    var activeElement = e.activeElement;
+    var content = e.cellContent;
+    
+    var at = content._tabIndices.indexOf(activeElement);
+    if(e.shiftKey) {
+        e.nextFocusableElement = content._tabIndices[(at >= 0) ? at - 1 : content._tabIndices.length  - 1];
     } else {
-        grid.classList.add("blur");
-        
-        loading_mask = document.createElement("ef-loader");
-        document.getElementById("container_div").appendChild(loading_mask);
+        e.nextFocusableElement = content._tabIndices[at + 1];
     }
 }
 
+var fields = ["id", "companyName", "custom1", "custom2", "market", "industry"];
+var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 });
+var columns = fields.map(function(f, idx) {
+    return {
+        field: f
+    };
+});
+columns[0].width = 60;
+columns[1].width = 120;
+
+columns[2].width = 100;
+columns[3].width = 100;
+columns[2].focusable = true;
+columns[3].focusable = true;
+columns[2].binding = buttonsBinding;
+columns[3].binding = buttonsBinding;
+
+var configObj = {
+    tabToFocus: true,
+    defaultColumnOptions: {
+        notRealTimeField: true,
+        textAlign: "c"
+    },
+    columns: columns,
+    tabNavigation: onTabNavigation,
+    staticDataRows: records
+};
+
+var grid = document.getElementById("grid");
+grid.config = configObj;
+
+window.addEventListener("keydown", function onKeyDown(e) {
+    if(e.keyCode === 9) {
+        key_indi.style.opacity = "1";
+        setTimeout(onHideKeyIndicator, 400);
+    }
+});
+function onHideKeyIndicator() {
+    key_indi.style.opacity = "";
+}
+
+

Copy and paste operations

+

Although Grid can get focus through Tab key, it does not get focus through mouse click by default. This is to allow mouse interaction with its content by not automatically shifting focus on Grid element (e.g., text selection requires focus to stay on the same element). If Grid does not contain any interactive content, you can listening to click event and put focus on the grid. To put the focus on Grid element, use focus() method from Grid's APIs.

+

Once Grid is in focus, you can catch native copy and paste events from Grid to manipulate or retrieve data from system clipboard. The example below shows how to populate data on Grid using clipboard data and setting Grid data to the clipboard.

+

Copying and pasting grid's content in TSV format example

+
html body {
+    padding: 5px;
+    box-sizing: border-box;
+}
+html hr {
+    margin: 5px;
+}
+efx-grid {
+    height: 200px;
+}
+efx-grid:focus-within { /* For illustrative purpose */
+    outline-width: 1px;
+    outline-style: solid;
+    outline-color: blue;
+}
+mark {
+    opacity: 0;
+    padding: 4px;
+    transition: opacity 0.5s ease-out;
+}
+textarea {
+    width: 100%;
+    height: 120px;
+}
+
+
<big>Try copying texts below and pasting them onto grid.</big>
+<hr>
+<textarea id="msg_ta"></textarea>
+<hr>
+<big>Try clicking grid and copying (<b>Ctrl/Command + C</b>) grid's content.</big>
+<br>
+<big>Then, paste the content on some other places.</big>
+<hr>
+<efx-grid id="grid"></efx-grid>
+<hr>
+<mark id="key_indi"></mark>
+
+
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
+await halo(); // This line is only required for demo purpose. It is not relevant for your application.
+
+/* ---------------------------------- Note ----------------------------------
+  DataGenerator, Formatters and extensions are exposed to global scope
+  in the bundle file to make it easier to create live examples.
+  Importing formatters and extensions is still required in your application. 
+  Please see the document for further information.
+---------------------------------------------------------------------------*/
+var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
+var dataset1 = DataGenerator.generateRecords(fields, { seed: 0, numRows: 4 });
+var dataset2 = DataGenerator.generateRecords(fields, { seed: 20, numRows: 7 });
+
+msg_ta.value = recordsToTSV(dataset2);
+msg_ta.addEventListener("focus", function(e) {
+    e.currentTarget.select();
+});
+
 var configObj = {
     columns: [
-        {name: "ID", field: fields[5], alignment: "center", width: 80},
         {name: "Company", field: fields[0]},
         {name: "Market", field: fields[1], width: 120},
         {name: "Last", field: fields[2], width: 100},
@@ -151,14 +336,71 @@ 

Basic Example

}; var grid = document.getElementById("grid"); -grid.addEventListener("configured", function(e) { - fetchData(); - var vScrollbar = e.detail.api.getCoreGrid().getVScrollbar(); - vScrollbar.listen("scroll", onScrollEnd); -}); grid.config = configObj; +grid.data = dataset1; + +grid.addEventListener("click", function onClick(e) { + grid.api.focus(); +}); +grid.addEventListener("copy", function onCopy(e) { + var columnNames = grid.api.getColumnNames(); + var rows = grid.api.getMultipleRowData(); // Get all row data from existing view + + // Build text in TSV format + var text = columnNames.join("\t") + "\n" + + rows.map(recordToTSV).join("\n"); + + e.clipboardData.setData("text/plain", text); + e.preventDefault(); + + showKeyIndicator("Data is copied to clipboard"); +}); +grid.addEventListener("paste", function onPaste(e) { + e.preventDefault(); + + var tsv = e.clipboardData.getData("text/plain"); + grid.data = tsvToRecords(tsv); + + showKeyIndicator("Data is pasted onto Grid"); +}); -document.getElementById("fetch_btn").addEventListener("click", fetchData); -document.getElementById("clear_btn").addEventListener("click", clearData); +function recordToTSV(record) { + return ([ + record[fields[0]], + record[fields[1]], + record[fields[2]], + record[fields[3]], + record[fields[4]] + ]).join("\t"); // TSV (Tab Separated Values) +} +function recordsToTSV(records) { + return records.map(recordToTSV).join("\n"); +} +function tsvToRecords(tsv) { + if(!tsv) { + return []; + } + var lines = tsv.split("\n"); + return lines.map(function(line) { + var obj = {}; + line.split("\t").map(function(item, idx) { + var field = fields[idx] || ""; + if(field) { + obj[field] = item; + } + }); + return obj; + }); +} +function showKeyIndicator(text) { + if(text) { + key_indi.textContent = text; + } + key_indi.style.opacity = "1"; + setTimeout(onHideKeyIndicator, 1000); +} +function onHideKeyIndicator() { + key_indi.style.opacity = ""; +}
-




+ \ No newline at end of file diff --git a/template-97.html b/template-97.html index fcf6f507..91ba0644 100644 --- a/template-97.html +++ b/template-97.html @@ -1,33 +1,19 @@ -

Pagination

-

Server Side Pagination

-

In case you want to retrieve a chunk of data from the server and do not want to load all of the data at once, you need to do server side pagination. The pagination component is enough to do this. Do not use the Pagination Extension for server side pagination.

-

All related logics (such as data requesting, validation, and transformation) must be implemented on the application side. Once data is received, you can just assign data to Grid's data property.

-

See more details about data setting at Columns and Data Properties.

-

Example

-
    function onServerResponse(data) {
-        hideLoadingMask();
-        grid.data = data; // Setting data from server
-    }
-    function onRowCountRecieved(total) {
-        pagination_ui.max = Math.ceil(total / PAGE_SIZE);
-    }
-    function onPageChanged(e) {
-        requestData(e.detail.value, PAGE_SIZE, onServerResponse);
-    }
-
-
efx-grid {
-    height: 169px;
+

Loading Mask

+

Loading mask is not part of Grid. To follow the standard theme, the UI and functionalities are provided by loader component. So, you need to put an overlay on top of the grid and not inside of it. For more advanced UI and behaviors, the implementation has to be done on the application side.

+

Basic Example

+
#container_div {
+    position: relative; /*ef-loader has position absolute*/
+    height: 250px;
 }
-ef-pagination {
-    margin-bottom: 30px;
-}
-.blur {
-    filter: blur(2px);
+efx-grid {
+    height: 100%;
 }
 
-
<div id="container_div">
+
<button id="show_btn">Show Masking</button>
+<button id="hide_btn">Hide Masking</button>
+<br><br>
+<div id="container_div">
     <efx-grid id="grid"></efx-grid>
-    <ef-pagination id='pagination_ui' value="1"></ef-pagination>
 </div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
@@ -39,59 +25,8 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var paginationUI = document.getElementById("pagination_ui"); -var SERVER_DELAY = 300; -var loading_mask = document.createElement("ef-loader"); -var PAGE_SIZE = 5; +var loadingMaskEl = document.createElement("ef-loader"); // Element can be created at runtime -function showLoadingMask() { - if (!loading_mask.parentElement) { - container_div.classList.add('blur'); - container_div.append(loading_mask); - } - - paginationUI.disabled = true; -} -function hideLoadingMask() { - if (loading_mask.parentElement) { - container_div.classList.remove('blur'); - loading_mask.parentElement.removeChild(loading_mask); - } - - paginationUI.disabled = false; -} - -// Event handlers -function onServerResponse(data) { - hideLoadingMask(); - grid.data = data; // Setting data from server -} -function onRowCountRecieved(total) { - paginationUI.max = Math.ceil(total / PAGE_SIZE); -} -function onPageChanged(e) { - requestData(e.detail.value, PAGE_SIZE, onServerResponse); -} - -// Mocking Server -function requestTotalPage(callback) { - setTimeout(function () { // Simulate network delay when requesting data from server - callback(serverData.length); - }, SERVER_DELAY); -} -function requestData(page, itemPerPage, callback) { - showLoadingMask(); - page = parseInt(page); - itemPerPage = parseInt(itemPerPage); - setTimeout(function () { // Simulate network delay when requesting data from server - var start = itemPerPage * (page - 1); - var end = start + itemPerPage; - callback(serverData.slice(start, end)); - }, SERVER_DELAY); -} - -// Mocking Data -var totalCount = 100; DataGenerator.addFieldInfo("rowNumber", { type: "function", generate: function(info, seed) { @@ -100,42 +35,48 @@

Example

count: 0, }); var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "rowNumber"]; -var serverData = DataGenerator.generateRecords(fields, { numRows: totalCount }); - -// Initializing UIs +var records = DataGenerator.generateRecords(fields, { numRows: 10 }); var configObj = { columns: [ - {name: "ID", field: fields[5], alignment: "center", width: 40}, + {name: "ID", field: fields[5], alignment: "center", width: 80}, {name: "Company", field: fields[0]}, {name: "Market", field: fields[1], width: 120}, {name: "Last", field: fields[2], width: 100}, {name: "Net. Chng", field: fields[3], width: 100}, {name: "Industry", field: fields[4]} - ] - // ,staticDataRows: {...} Initial data is optional + ], + staticDataRows: records }; var grid = document.getElementById("grid"); grid.config = configObj; -paginationUI.addEventListener("value-changed", onPageChanged); +document.getElementById("show_btn").addEventListener("click", function() { + document.getElementById("container_div").appendChild(loadingMaskEl); +}); -// Start app by getting total number of items and data -requestTotalPage(onRowCountRecieved); -requestData(paginationUI.value, PAGE_SIZE, onServerResponse); +document.getElementById("hide_btn").addEventListener("click", function() { + loadingMaskEl.remove(); +});
-

Client side pagination

-

If you have all the data available on the client side and want to show data in pagination style, you can use the Pagination Extension and the pagination element. The current page and page size can be configured using the pagination option. The pagination behaviors are then implemented by the extension. See Pagination Extension for more details.

-

Example

-
efx-grid {
-    height: 169px;
+

Infinite Scrolling with Data Fetching Example

+
efx-grid {
+    height: 250px;
+}
+.blur {
+    filter: blur(2px);
 }
-ef-pagination {
-    margin-bottom: 30px;
+#container_div {
+    position: relative; /*ef-loader has position absolute*/
 }
 
-
<efx-grid id="grid"></efx-grid>
-<ef-pagination id='pagination'></ef-pagination>
+
<button id="fetch_btn">Fetch Data</button>
+<button id="clear_btn">Clear Data</button>
+<big>Total rows: <span id="total_row">0</span></big>
+<br>
+<div id="container_div">
+    <efx-grid id="grid"></efx-grid>
+</div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -146,6 +87,7 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ +var loading_mask = null; // Cache the element for re-using multiple times DataGenerator.addFieldInfo("rowNumber", { type: "function", generate: function(info, seed) { @@ -154,28 +96,69 @@

Example

count: 0, }); var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "rowNumber"]; -var records = DataGenerator.generateRecords(fields, { numRows: 100 }); + +function fetchData() { // Simulate Data Fetching + if (!loading_mask) { // If we are not loading anything + toggleLoadingMask(); + setTimeout(onDataReceived, 1500); // Simulate delay for communication with a server + } +}; + +function clearData() { + grid.api.removeAllRows(); + document.getElementById("total_row").textContent = 0; +}; + +function onDataReceived() { + toggleLoadingMask(); // Remove loading mask + + var records = DataGenerator.generateRecords(fields, { numRows: 20 }); + grid.api.addStaticDataRows(records); + + document.getElementById("total_row").textContent = grid.api.getRowCount(); // Update UI +} + +function onScrollEnd(e) { + var vScrollbar = grid.api.getCoreGrid().getVScrollbar(); + if (vScrollbar.isEndOfVerticalScroll()) { + fetchData(); + } +} + +function toggleLoadingMask() { + if (loading_mask) { + grid.classList.remove("blur"); + + loading_mask.remove(); + loading_mask = null; + } else { + grid.classList.add("blur"); + + loading_mask = document.createElement("ef-loader"); + document.getElementById("container_div").appendChild(loading_mask); + } +} + var configObj = { columns: [ - {name: "ID", field: fields[5], alignment: "center", width: 40}, + {name: "ID", field: fields[5], alignment: "center", width: 80}, {name: "Company", field: fields[0]}, {name: "Market", field: fields[1], width: 120}, {name: "Last", field: fields[2], width: 100}, {name: "Net. Chng", field: fields[3], width: 100}, {name: "Industry", field: fields[4]} - ], - staticDataRows: records, - pagination: { - element: document.getElementById("pagination"), - page: 1, - pageSize: 5 - }, - extensions: [ - new Pagination() ] }; var grid = document.getElementById("grid"); +grid.addEventListener("configured", function(e) { + fetchData(); + var vScrollbar = e.detail.api.getCoreGrid().getVScrollbar(); + vScrollbar.listen("scroll", onScrollEnd); +}); grid.config = configObj; + +document.getElementById("fetch_btn").addEventListener("click", fetchData); +document.getElementById("clear_btn").addEventListener("click", clearData);
- \ No newline at end of file +




diff --git a/template-98.html b/template-98.html index f5e466f2..fcf6f507 100644 --- a/template-98.html +++ b/template-98.html @@ -1,10 +1,34 @@ -

Row Span

-

Setting row span on a cell can be done through Core Grid API (e.g., setCellRowSpan). A cell with row span will simply be expanded on top of cells below it. Cells are not actually merged by row span, but appeared as if they are merged together.

-

Since cells in grid are reused across multiple rows by default, rowVirtualization need to be turned off for row span to work properly.

-

Row virtualization mode

-

Grid does not support row span in row virtualization mode. The row virtualization mode can be set using rowVirtualization: false in the configs.

-

Example 1: setting row span after initialization

-
<efx-grid id="grid"></efx-grid>
+

Pagination

+

Server Side Pagination

+

In case you want to retrieve a chunk of data from the server and do not want to load all of the data at once, you need to do server side pagination. The pagination component is enough to do this. Do not use the Pagination Extension for server side pagination.

+

All related logics (such as data requesting, validation, and transformation) must be implemented on the application side. Once data is received, you can just assign data to Grid's data property.

+

See more details about data setting at Columns and Data Properties.

+

Example

+
    function onServerResponse(data) {
+        hideLoadingMask();
+        grid.data = data; // Setting data from server
+    }
+    function onRowCountRecieved(total) {
+        pagination_ui.max = Math.ceil(total / PAGE_SIZE);
+    }
+    function onPageChanged(e) {
+        requestData(e.detail.value, PAGE_SIZE, onServerResponse);
+    }
+
+
efx-grid {
+    height: 169px;
+}
+ef-pagination {
+    margin-bottom: 30px;
+}
+.blur {
+    filter: blur(2px);
+}
+
+
<div id="container_div">
+    <efx-grid id="grid"></efx-grid>
+    <ef-pagination id='pagination_ui' value="1"></ef-pagination>
+</div>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -15,37 +39,103 @@ 

Example 1: setting row Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["id", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 10 }); +var paginationUI = document.getElementById("pagination_ui"); +var SERVER_DELAY = 300; +var loading_mask = document.createElement("ef-loader"); +var PAGE_SIZE = 5; + +function showLoadingMask() { + if (!loading_mask.parentElement) { + container_div.classList.add('blur'); + container_div.append(loading_mask); + } + + paginationUI.disabled = true; +} +function hideLoadingMask() { + if (loading_mask.parentElement) { + container_div.classList.remove('blur'); + loading_mask.parentElement.removeChild(loading_mask); + } + + paginationUI.disabled = false; +} + +// Event handlers +function onServerResponse(data) { + hideLoadingMask(); + grid.data = data; // Setting data from server +} +function onRowCountRecieved(total) { + paginationUI.max = Math.ceil(total / PAGE_SIZE); +} +function onPageChanged(e) { + requestData(e.detail.value, PAGE_SIZE, onServerResponse); +} + +// Mocking Server +function requestTotalPage(callback) { + setTimeout(function () { // Simulate network delay when requesting data from server + callback(serverData.length); + }, SERVER_DELAY); +} +function requestData(page, itemPerPage, callback) { + showLoadingMask(); + page = parseInt(page); + itemPerPage = parseInt(itemPerPage); + setTimeout(function () { // Simulate network delay when requesting data from server + var start = itemPerPage * (page - 1); + var end = start + itemPerPage; + callback(serverData.slice(start, end)); + }, SERVER_DELAY); +} + +// Mocking Data +var totalCount = 100; +DataGenerator.addFieldInfo("rowNumber", { + type: "function", + generate: function(info, seed) { + return ++info.count; + }, + count: 0, +}); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "rowNumber"]; +var serverData = DataGenerator.generateRecords(fields, { numRows: totalCount }); + +// Initializing UIs var configObj = { - rowVirtualization: false, columns: [ - {name: "Row Index", field: fields[0], width: 60}, + {name: "ID", field: fields[5], alignment: "center", width: 40}, + {name: "Company", field: fields[0]}, {name: "Market", field: fields[1], width: 120}, {name: "Last", field: fields[2], width: 100}, {name: "Net. Chng", field: fields[3], width: 100}, {name: "Industry", field: fields[4]} - ], - staticDataRows: records + ] + // ,staticDataRows: {...} Initial data is optional }; var grid = document.getElementById("grid"); -grid.addEventListener("configured", function(e) { - var core = e.detail.api.getCoreGrid(); - var section = core.getSection('content'); - section.setCellRowSpan(1, 0, 2); - section.setCellRowSpan(4, 4, 3); - section.setCellRowSpan(0, 4, 4); -}); grid.config = configObj; + +paginationUI.addEventListener("value-changed", onPageChanged); + +// Start app by getting total number of items and data +requestTotalPage(onRowCountRecieved); +requestData(paginationUI.value, PAGE_SIZE, onServerResponse);

-

Example 2: setting row span in data binding

-
efx-grid {
-    height: 300px;
-    margin-bottom: 40px;
+

Client side pagination

+

If you have all the data available on the client side and want to show data in pagination style, you can use the Pagination Extension and the pagination element. The current page and page size can be configured using the pagination option. The pagination behaviors are then implemented by the extension. See Pagination Extension for more details.

+

Example

+
efx-grid {
+    height: 169px;
+}
+ef-pagination {
+    margin-bottom: 30px;
 }
 
<efx-grid id="grid"></efx-grid>
+<ef-pagination id='pagination'></ef-pagination>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -56,30 +146,36 @@ 

Example 1: setting row Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["id", "companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"]; -var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 }); - -var onCustomBinding = function(e) { - if(e.rowIndex % 2 === 0) { - e.section.setCellRowSpan(e.colIndex, e.rowIndex, 2); - } - e.cell.setContent(e.data); -}; - +DataGenerator.addFieldInfo("rowNumber", { + type: "function", + generate: function(info, seed) { + return ++info.count; + }, + count: 0, +}); +var fields = ["companyName", "market", "CF_LAST", "CF_NETCHNG", "industry", "rowNumber"]; +var records = DataGenerator.generateRecords(fields, { numRows: 100 }); var configObj = { - rowVirtualization: false, columns: [ - {name: "Row Index", field: fields[0], width: 60}, - {name: "Company Name", field: fields[1], width: 120, binding: onCustomBinding}, - {name: "Market", field: fields[2], width: 120, binding: onCustomBinding}, - {name: "Last", field: fields[3], width: 100}, - {name: "Net. Chng", field: fields[4], width: 100}, - {name: "Industry", field: fields[5]} + {name: "ID", field: fields[5], alignment: "center", width: 40}, + {name: "Company", field: fields[0]}, + {name: "Market", field: fields[1], width: 120}, + {name: "Last", field: fields[2], width: 100}, + {name: "Net. Chng", field: fields[3], width: 100}, + {name: "Industry", field: fields[4]} ], - staticDataRows: records + staticDataRows: records, + pagination: { + element: document.getElementById("pagination"), + page: 1, + pageSize: 5 + }, + extensions: [ + new Pagination() + ] }; var grid = document.getElementById("grid"); grid.config = configObj;

-




+ \ No newline at end of file diff --git a/template-99.html b/template-99.html index 8556fbd6..f5e466f2 100644 --- a/template-99.html +++ b/template-99.html @@ -1,17 +1,10 @@ -

Text Selection

-

Text selection has 2 scopes. It's grid scope and column scope. The default value of text selection is disabled, but you can enable it. If you enable it, users can select text in scope.

-
    -
  • The grid scope can enable by set textSelect property to true in configuration of Grid
  • -
  • The column scope can enable by set textSelect property to true in configuration of Columns
  • -
-

Limitation with safari

-
    -
  • When you use Text selection with Row Dragging, Safari is unable to select text.
  • -
  • Safari is unable to listening pointer events such as clicks, hovers, and so on. When you use Custom Formatter in a cell, it looks like this example.
  • -
-

Example

-

If you use Safari, try clicking the button in column Market from the sample below. You won't be able to receive the click event.

-
<efx-grid id="grid"></efx-grid>
+

Row Span

+

Setting row span on a cell can be done through Core Grid API (e.g., setCellRowSpan). A cell with row span will simply be expanded on top of cells below it. Cells are not actually merged by row span, but appeared as if they are merged together.

+

Since cells in grid are reused across multiple rows by default, rowVirtualization need to be turned off for row span to work properly.

+

Row virtualization mode

+

Grid does not support row span in row virtualization mode. The row virtualization mode can be set using rowVirtualization: false in the configs.

+

Example 1: setting row span after initialization

+
<efx-grid id="grid"></efx-grid>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -22,54 +15,37 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = ["companyName", "market"]; -var records = DataGenerator.generateRecords(fields, { numRows: 10 }); -var buttonDisplay = { -binding: function (e) { - var cellData = e.cell; - var buttonContent = document.createElement("button"); - var spanContent = document.createElement("span"); - buttonContent.addEventListener("click" , () => { - alert(e.data); - }); - spanContent.textContent = `${e.data}`; - buttonContent.appendChild(spanContent); - cellData.setContent(buttonContent); - } -}; - +var fields = ["id", "market", "CF_LAST", "CF_NETCHNG", "industry"]; +var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 10 }); var configObj = { - rowVirtualRendering: false, - textSelect : true, + rowVirtualization: false, columns: [ - {name: "Company", field: fields[0]}, - {name: "Market", field: fields[1], formatter: buttonDisplay , width: 120} + {name: "Row Index", field: fields[0], width: 60}, + {name: "Market", field: fields[1], width: 120}, + {name: "Last", field: fields[2], width: 100}, + {name: "Net. Chng", field: fields[3], width: 100}, + {name: "Industry", field: fields[4]} ], staticDataRows: records }; var grid = document.getElementById("grid"); +grid.addEventListener("configured", function(e) { + var core = e.detail.api.getCoreGrid(); + var section = core.getSection('content'); + section.setCellRowSpan(1, 0, 2); + section.setCellRowSpan(4, 4, 3); + section.setCellRowSpan(0, 4, 4); +}); grid.config = configObj;
-

Limitation with row virtualization

-

Text selection with row virtualization cannot select all data in the grid. -In the example below, the grid has text selection enabled and uses row virtualization. -When you try to select and copy text from the grid and paste it into a text area, you will see that not all data from the grid is obtained. -This is because row virtualization render only the rows that is visible in the grid's viewport. -For example, if you have 50 rows of data, but the grid can only show the first 10 rows at a time, then when you try to select the text, it will only select the first 14 rows (10 rows + buffer rows). -If you want to know about row virtualization in more detail, you can refer to the Understanding row virtualization section in the Custom Formatter page.

-

Example

-
efx-grid {
+

Example 2: setting row span in data binding

+
efx-grid {
     height: 300px;
-}
-textarea {
-    height: 200px;
-    width: 100%;
+    margin-bottom: 40px;
 }
 
<efx-grid id="grid"></efx-grid>
-<hr>
-<textarea placeholder="Paste text here"></textarea>
 
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
 await halo(); // This line is only required for demo purpose. It is not relevant for your application.
@@ -80,159 +56,30 @@ 

Example

Importing formatters and extensions is still required in your application. Please see the document for further information. ---------------------------------------------------------------------------*/ -var fields = [ - "id", - "companyName", - "market", - "CF_LAST", - "CF_NETCHNG", - "industry" -]; -var records = DataGenerator.generateRecords(fields, { numRows: 50, seed: 0 }); -var config = { - textSelect: true, - columns: [ - { - field: fields[0], - name: "ID" - }, - { - field: fields[1], - name: "Company Name" - }, - { - field: fields[2], - name: "Market" - }, - { - field: fields[3], - name: "Last" - }, - { - field: fields[4], - name: "Net. Chng" - }, - { - field: fields[5], - name: "Industry" - }, - ], - staticDataRows: records -}; - -var grid = document.getElementById("grid"); -grid.config = config; -window.grid = grid; -
-

Copying all content in the grid without text selection

-

If you want to copy all the data in the grid, you can do it by focusing on the grid element and modifying the clipboard without text selection. -To do this, you can listen for the click event on the grid element and call focus method on the grid API to focus on the grid. -Then, you can listen for the copy event on the grid element and modify the clipboard as shown in the example below.

-

Example

-
html body {
-    padding: 5px;
-    box-sizing: border-box;
-}
-html hr {
-    margin: 5px;
-}
-efx-grid {
-    height: 200px;
-}
-efx-grid:focus-within {
-    outline-width: 1px;
-    outline-style: solid;
-    outline-color: blue;
-}
-textarea {
-    width: 100%;
-    height: 200px;
-}
-mark {
-    opacity: 0;
-    padding: 4px;
-    transition: opacity 0.5s ease-out;
-}
-
-
<big>Try clicking grid and copying (<b>Ctrl/Command + C</b>) grid's content.</big>
-<br>
-<big>Then, paste the content on the text box below.</big>
-<hr>
-<mark id="key_indi"></mark>
-<hr>
-<efx-grid id="grid"></efx-grid>
-<hr>
-<textarea placeholder="Paste clipboard content here"></textarea>
-
-
import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
-await halo(); // This line is only required for demo purpose. It is not relevant for your application.
-
-/* ---------------------------------- Note ----------------------------------
-  DataGenerator, Formatters and extensions are exposed to global scope
-  in the bundle file to make it easier to create live examples.
-  Importing formatters and extensions is still required in your application. 
-  Please see the document for further information.
----------------------------------------------------------------------------*/
-
 var fields = ["id", "companyName", "market", "CF_LAST", "CF_NETCHNG", "industry"];
 var records = DataGenerator.generateRecords(fields, { seed: 0, numRows: 20 });
 
-function onClick(e) {
-    grid.api.focus();
-}
-function onCopy(e) {
-    var columnNames = grid.api.getColumnNames();
-    var rows = grid.api.getMultipleRowData(); // Get all row data from existing view
-    
-    // Build text in TSV format 
-    var text = columnNames.join("\t") + "\n" +
-        rows.map(recordToTSV).join("\n");
-    
-    e.clipboardData.setData("text/plain", text);
-    e.preventDefault();
-    
-    showKeyIndicator("Data is copied to clipboard");
-}
-function recordToTSV(record) {
-    return ([
-        record[fields[0]],
-        record[fields[1]],
-        record[fields[2]],
-        record[fields[3]],
-        record[fields[4]]
-    ]).join("\t"); // TSV (Tab Separated Values)
-}
-function showKeyIndicator(text) {
-    if(text) {
-        key_indi.textContent = text;
+var onCustomBinding = function(e) {
+    if(e.rowIndex % 2 === 0) {
+        e.section.setCellRowSpan(e.colIndex, e.rowIndex, 2);
     }
-    key_indi.style.opacity = "1";
-    setTimeout(onHideKeyIndicator, 1000);
-}
-function onHideKeyIndicator() {
-    key_indi.style.opacity = "";
-}
+    e.cell.setContent(e.data);
+};
 
 var configObj = {
-    sorting: {
-        sortableColumns: true
-    },
+    rowVirtualization: false,
     columns: [
-        { name: "Id", field: fields[0], width: 40 },
-        { name: "Company", field: fields[1] },
-        { name: "Market", field: fields[2], width: 100 },
-        { name: "Last", field: fields[3], width: 80 },
-        { name: "Net. Chng", field: fields[4], width: 80 },
-        { name: "Industry", field: fields[5] }
+        {name: "Row Index", field: fields[0], width: 60},
+        {name: "Company Name", field: fields[1], width: 120, binding: onCustomBinding},
+        {name: "Market", field: fields[2], width: 120, binding: onCustomBinding},
+        {name: "Last", field: fields[3], width: 100},
+        {name: "Net. Chng", field: fields[4], width: 100},
+        {name: "Industry", field: fields[5]}
     ],
-    staticDataRows: records,
-    extensions: []
+    staticDataRows: records
 };
 
 var grid = document.getElementById("grid");
 grid.config = configObj;
-
-grid.addEventListener("click", onClick);
-grid.addEventListener("copy", onCopy);
 
-



+