@vaadin/vaadin-grid
Advanced tools
@@ -18,3 +18,3 @@ { | ||
"name": "@vaadin/vaadin-grid", | ||
"version": "5.2.0-alpha2", | ||
"version": "5.2.0-alpha3", | ||
"main": "vaadin-grid.js", | ||
@@ -21,0 +21,0 @@ "author": "Vaadin Ltd", |
@@ -32,21 +32,16 @@ [](https://badge.fury.io/js/%40vaadin%2Fvaadin-grid) | ||
<vaadin-grid theme="row-dividers" column-reordering-allowed multi-sort> | ||
<vaadin-grid-selection-column auto-select frozen> </vaadin-grid-selection-column> | ||
<vaadin-grid-selection-column auto-select frozen></vaadin-grid-selection-column> | ||
<vaadin-grid-column width="9em" path="firstName"></vaadin-grid-column> | ||
<vaadin-grid-column width="9em" path="lastName"></vaadin-grid-column> | ||
<vaadin-grid-column id="address-column" width="15em" flex-grow="2" path="address.street" label="Address"></vaadin-grid-column> | ||
<vaadin-grid-column id="addresscolumn" width="15em" flex-grow="2" header="Address"></vaadin-grid-column> | ||
</vaadin-grid> | ||
<script> | ||
const grid = document.querySelector('vaadin-grid'); | ||
// Customize the "Address" column's renderer | ||
document.querySelector('#address-column').renderer = (root, grid, model) => { | ||
root.textContent = `${model.item.address.street}, ${model.item.address.city}`; | ||
document.querySelector('#addresscolumn').renderer = (root, grid, rowData) => { | ||
root.textContent = `${rowData.item.address.street}, ${rowData.item.address.city}`; | ||
}; | ||
// Populate the grid with data | ||
const grid = document.querySelector('vaadin-grid'); | ||
fetch('https://demo.vaadin.com/demo-data/1.0/people?count=200') | ||
@@ -53,0 +48,0 @@ .then(res => res.json()) |
import './vaadin-grid.js'; | ||
import './vaadin-grid-column-group.js'; | ||
import './vaadin-grid-filter.js'; | ||
import './vaadin-grid-filter-column.js'; | ||
import './vaadin-grid-sorter.js'; | ||
@@ -10,3 +11,3 @@ import './vaadin-grid-selection-column.js'; | ||
@license | ||
Copyright (c) 2017 Vaadin Ltd. | ||
Copyright (c) 2018 Vaadin Ltd. | ||
This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ | ||
@@ -13,0 +14,0 @@ */ |
@@ -17,3 +17,3 @@ /** | ||
_a11yGetHeaderRowCount(_columnTree) { | ||
return _columnTree.filter(level => level.some(col => col._headerTemplate || col.headerRenderer || col.path || col.label)).length; | ||
return _columnTree.filter(level => level.some(col => col._headerTemplate || col.headerRenderer || col.path || col.header)).length; | ||
} | ||
@@ -20,0 +20,0 @@ |
/** | ||
@license | ||
Copyright (c) 2017 Vaadin Ltd. | ||
Copyright (c) 2018 Vaadin Ltd. | ||
This program is available under Apache License Version 2.0, available at https://vaadin.com/license/ | ||
@@ -62,5 +62,5 @@ */ | ||
/** | ||
* Shown in the header cell of the column. | ||
* Text content to display in the header cell of the column. | ||
*/ | ||
label: { | ||
header: { | ||
type: String | ||
@@ -70,3 +70,4 @@ }, | ||
/** | ||
* Aligns the columns cell content horizontally to either start, center or end | ||
* Aligns the columns cell content horizontally. | ||
* Supported values: "start", "center" and "end". | ||
*/ | ||
@@ -119,3 +120,3 @@ textAlign: { | ||
'_flexGrowChanged(flexGrow, _headerCell, _footerCell, _cells.*)', | ||
'_pathOrLabelChanged(path, label, _headerCell, _footerCell, _cells.*, renderer, headerRenderer, _bodyTemplate, _headerTemplate)', | ||
'_pathOrHeaderChanged(path, header, _headerCell, _footerCell, _cells.*, renderer, headerRenderer, _bodyTemplate, _headerTemplate)', | ||
'_textAlignChanged(textAlign, _cells.*, _headerCell, _footerCell)', | ||
@@ -241,6 +242,6 @@ '_orderChanged(_order, _headerCell, _footerCell, _cells.*)', | ||
__runRenderer(renderer, cell, model) { | ||
__runRenderer(renderer, cell, rowData) { | ||
const args = [cell._content, this]; | ||
if (model && model.item) { | ||
args.push(model); | ||
if (rowData && rowData.item) { | ||
args.push(rowData); | ||
} | ||
@@ -256,3 +257,3 @@ renderer.apply(this, args); | ||
cells.forEach(cell => { | ||
const model = {item: cell.parentElement._item, index: cell.parentElement.index}; | ||
const model = this._grid.__getRowModel(cell.parentElement); | ||
@@ -269,2 +270,3 @@ if (renderer) { | ||
cell._content.innerHTML = ''; | ||
template.templatizer._grid = template.templatizer._grid || this._grid; | ||
const inst = template.templatizer.createInstance(); | ||
@@ -358,5 +360,6 @@ cell._content.appendChild(inst.root); | ||
_pathOrLabelChanged(path, label, headerCell, footerCell, cells, renderer, headerRenderer, bodyTemplate, headerTemplate) { | ||
if (!headerRenderer && !headerTemplate && label !== undefined && headerCell) { | ||
headerCell._content.textContent = label; | ||
_pathOrHeaderChanged(path, header, headerCell, footerCell, cells, renderer, headerRenderer, bodyTemplate, headerTemplate) { | ||
if (!headerRenderer && !headerTemplate && header !== undefined && headerCell) { | ||
headerCell._content.textContent = header; | ||
headerCell.parentElement.hidden = false; | ||
} | ||
@@ -367,13 +370,7 @@ | ||
const pathRenderer = (root, owner, {item}) => root.textContent = this.get(path, item); | ||
cells.value.forEach(cell => cell._renderer = pathRenderer); | ||
this._grid._update(); | ||
this.__setColumnTemplateOrRenderer(undefined, pathRenderer, cells.value); | ||
} | ||
if (!headerRenderer && !headerTemplate && !label && headerCell) { | ||
const generatedLabel = path | ||
.substr(path.lastIndexOf('.') + 1) | ||
.replace(/([A-Z])/g, '-$1').toLowerCase() | ||
.replace(/-/, ' ') | ||
.replace(/\w\S*/g, str => str.charAt(0).toUpperCase() + str.substr(1)); | ||
headerCell._content.textContent = generatedLabel; | ||
if (!headerRenderer && !headerTemplate && !header && headerCell) { | ||
headerCell._content.textContent = this._generateHeader(path); | ||
headerCell.parentElement.hidden = false; | ||
@@ -384,2 +381,10 @@ } | ||
_generateHeader(path) { | ||
return path | ||
.substr(path.lastIndexOf('.') + 1) | ||
.replace(/([A-Z])/g, '-$1').toLowerCase() | ||
.replace(/-/g, ' ') | ||
.replace(/\w\S*/g, str => str.charAt(0).toUpperCase() + str.substr(1)); | ||
} | ||
_toggleAttribute(name, bool, node) { | ||
@@ -426,2 +431,6 @@ if (node.hasAttribute(name) === !bool) { | ||
} | ||
if (['start', 'end', 'center'].indexOf(textAlign) === -1) { | ||
console.warn('textAlign can only be set as "start", "end" or "center"'); | ||
return; | ||
} | ||
@@ -507,9 +516,6 @@ let textAlignFallback; | ||
* - `column` The `<vaadin-grid-column>` element. | ||
* - `model` The object with the properties related with | ||
* - `rowData` The object with the properties related with | ||
* the rendered item, contains: | ||
* - `model.index` The index of the item. | ||
* - `model.item` The item. | ||
* | ||
* **NOTE:** The renderer callback can be called multiple times | ||
* with the previous content. | ||
* - `rowData.index` The index of the item. | ||
* - `rowData.item` The item. | ||
*/ | ||
@@ -520,3 +526,3 @@ renderer: Function, | ||
* Path to an item sub-property whose value gets displayed in the column body cells. | ||
* The property name is also shown in the column header if an explicit label/renderer isn't defined. | ||
* The property name is also shown in the column header if an explicit header or renderer isn't defined. | ||
*/ | ||
@@ -523,0 +529,0 @@ path: { |
@@ -334,3 +334,3 @@ /** | ||
}); | ||
this._cache.size = this.size; | ||
this._cache.size = this.size || 0; | ||
this._cache.updateSize(); | ||
@@ -337,0 +337,0 @@ this._hasData = false; |
@@ -127,12 +127,14 @@ /** | ||
_updateLastColumn() { | ||
Array.from(this.shadowRoot.querySelectorAll('tr')).forEach(row => { | ||
Array.from(row.querySelectorAll('[part~="cell"]:not([part~="details-cell"])')) | ||
.sort((a, b) => { | ||
return a._column._order - b._column._order; | ||
}).forEach((cell, cellIndex, children) => { | ||
this._toggleAttribute('last-column', cellIndex === children.length - 1, cell); | ||
}); | ||
}); | ||
Array.from(this.shadowRoot.querySelectorAll('tr')).forEach(row => this._updateLastColumnForRow(row)); | ||
} | ||
_updateLastColumnForRow(row) { | ||
Array.from(row.querySelectorAll('[part~="cell"]:not([part~="details-cell"])')) | ||
.sort((a, b) => { | ||
return a._column._order - b._column._order; | ||
}).forEach((cell, cellIndex, children) => { | ||
this._toggleAttribute('last-column', cellIndex === children.length - 1, cell); | ||
}); | ||
} | ||
_isColumnElement(node) { | ||
@@ -139,0 +141,0 @@ return node.nodeType === Node.ELEMENT_NODE && /\bcolumn\b/.test(node.localName); |
@@ -36,2 +36,3 @@ /** | ||
display: inline-flex; | ||
max-width: 100%; | ||
} | ||
@@ -38,0 +39,0 @@ |
@@ -34,9 +34,6 @@ /** | ||
* - `grid` The `<vaadin-grid>` element. | ||
* - `model` The object with the properties related with | ||
* - `rowData` The object with the properties related with | ||
* the rendered item, contains: | ||
* - `model.index` The index of the item. | ||
* - `model.item` The item. | ||
* | ||
* **NOTE:** The renderer callback can be called multiple times | ||
* with the previous content. | ||
* - `rowData.index` The index of the item. | ||
* - `rowData.item` The item. | ||
*/ | ||
@@ -110,4 +107,9 @@ rowDetailsRenderer: Function, | ||
const cell = row.querySelector('[part~="details-cell"]'); | ||
if (!cell) { | ||
return; | ||
} | ||
const detailsHidden = !this._isDetailsOpened(item); | ||
if (cell && (!cell._instance && !cell._renderer || cell.hidden !== detailsHidden)) { | ||
const hiddenChanged = !!cell.hidden !== detailsHidden; | ||
if (!cell._instance && !cell._renderer || cell.hidden !== detailsHidden) { | ||
cell.hidden = detailsHidden; | ||
@@ -132,4 +134,6 @@ if (detailsHidden) { | ||
} | ||
this._updateMetrics(); | ||
this._positionItems(); | ||
if (hiddenChanged) { | ||
this._updateMetrics(); | ||
this._positionItems(); | ||
} | ||
} | ||
@@ -136,0 +140,0 @@ |
@@ -8,3 +8,3 @@ /** | ||
import { animationFrame } from '@polymer/polymer/lib/utils/async.js'; | ||
import { idlePeriod, animationFrame } from '@polymer/polymer/lib/utils/async.js'; | ||
import { flush } from '@polymer/polymer/lib/utils/flush.js'; | ||
@@ -171,3 +171,3 @@ import { PolymerIronList } from './iron-list.js'; | ||
_increasePoolIfNeeded(count) { | ||
if ((count === 0 && this._scrollingToIndex) || !this._canPopulate()) { | ||
if ((count === 0 && this._scrollingToIndex) || !this._canPopulate() || !this._effectiveSize) { | ||
return; | ||
@@ -179,28 +179,15 @@ } | ||
super._increasePoolIfNeeded(25); | ||
} else { | ||
} else if (this._optPhysicalSize !== Infinity) { | ||
this._debounceIncreasePool = Debouncer.debounce( | ||
this._debounceIncreasePool, | ||
animationFrame, | ||
idlePeriod, | ||
() => { | ||
this._updateMetrics(); | ||
const viewportCovered = this._physicalCount * this._physicalAverage >= this._viewportHeight * 3; | ||
// Don't increase the pool if there's enough rows. This is to avoid an eternal loop. | ||
if (!viewportCovered) { | ||
this._accessIronListAPI(() => super._increasePoolIfNeeded(count)); | ||
const remainingPhysicalSize = this._optPhysicalSize - this._physicalSize; | ||
const estimatedMissingRowCount = Math.ceil(remainingPhysicalSize / this._physicalAverage); | ||
if (count) { | ||
const childNodes = Array.from(this.$.items.childNodes); | ||
// Ensure the rows are in order after increasing pool | ||
const rowsInOrder = !!childNodes.reduce((inOrder, current, currentIndex, array) => { | ||
if (currentIndex === 0 || array[currentIndex - 1].index === current.index - 1) { | ||
return inOrder; | ||
} | ||
}, true); | ||
if (!rowsInOrder) { | ||
childNodes.sort((row1, row2) => { | ||
return row1.index - row2.index; | ||
}).forEach(row => this.$.items.appendChild(row)); | ||
} | ||
} | ||
if (this._physicalSize && estimatedMissingRowCount > 0) { | ||
super._increasePoolIfNeeded(estimatedMissingRowCount); | ||
// Ensure the rows are in order after increasing pool | ||
this.__reorderChildNodes(); | ||
} | ||
@@ -211,2 +198,17 @@ }); | ||
__reorderChildNodes() { | ||
const childNodes = Array.from(this.$.items.childNodes); | ||
const rowsInOrder = !!childNodes.reduce((inOrder, current, currentIndex, array) => { | ||
if (currentIndex === 0 || array[currentIndex - 1].index === current.index - 1) { | ||
return inOrder; | ||
} | ||
}, true); | ||
if (!rowsInOrder) { | ||
childNodes.sort((row1, row2) => { | ||
return row1.index - row2.index; | ||
}).forEach(row => this.$.items.appendChild(row)); | ||
} | ||
} | ||
_createPool(size) { | ||
@@ -213,0 +215,0 @@ const fragment = document.createDocumentFragment(); |
@@ -51,3 +51,3 @@ /** | ||
* | ||
* Use the [`<vaadin-grid-column>`](#/elements/vaadin-grid-column) element to configure the grid columns. Set `path` and `label` | ||
* Use the [`<vaadin-grid-column>`](#/elements/vaadin-grid-column) element to configure the grid columns. Set `path` and `header` | ||
* shorthand properties for the columns to define what gets rendered in the cells of the column. | ||
@@ -58,4 +58,4 @@ * | ||
* <vaadin-grid> | ||
* <vaadin-grid-column path="name.first" label="First Name"></vaadin-grid-column> | ||
* <vaadin-grid-column path="name.last" label="Last Name"></vaadin-grid-column> | ||
* <vaadin-grid-column path="name.first" header="First Name"></vaadin-grid-column> | ||
* <vaadin-grid-column path="name.last" header="Last Name"></vaadin-grid-column> | ||
* <vaadin-grid-column path="email"></vaadin-grid-column> | ||
@@ -68,3 +68,3 @@ * </vaadin-grid> | ||
* | ||
* Each of those renderer functions provides `root`, `column`, `model` arguments when applicable. | ||
* Each of those renderer functions provides `root`, `column`, `rowData` arguments when applicable. | ||
* Generate DOM content, append it to the `root` element and control the state | ||
@@ -74,2 +74,7 @@ * of the host element by accessing `column`. Before generating new content, | ||
* | ||
* Renderers are called on initialization of new column cells and each time the | ||
* related row data is updated. DOM generated during the renderer call can be reused | ||
* in the next renderer call and will be provided with the `root` argument. | ||
* On first call it will be empty. | ||
* | ||
* #### Example: | ||
@@ -93,4 +98,4 @@ * ```html | ||
* }; | ||
* columns[0].renderer = function(root, column, model) { | ||
* root.textContent = model.item.name; | ||
* columns[0].renderer = function(root, column, rowData) { | ||
* root.textContent = rowData.item.name; | ||
* }; | ||
@@ -101,4 +106,4 @@ * | ||
* }; | ||
* columns[1].renderer = function(root, column, model) { | ||
* root.textContent = model.item.surname; | ||
* columns[1].renderer = function(root, column, rowData) { | ||
* root.textContent = rowData.item.surname; | ||
* }; | ||
@@ -109,4 +114,4 @@ * | ||
* }; | ||
* columns[2].renderer = function(root, column, model) { | ||
* root.textContent = model.item.role; | ||
* columns[2].renderer = function(root, column, rowData) { | ||
* root.textContent = rowData.item.role; | ||
* }; | ||
@@ -314,3 +319,3 @@ * ``` | ||
static get version() { | ||
return '5.2.0-alpha2'; | ||
return '5.2.0-alpha3'; | ||
} | ||
@@ -534,3 +539,3 @@ | ||
this._frozenCellsChanged(); | ||
this._updateLastColumn(); | ||
this._updateLastColumnForRow(row); | ||
} | ||
@@ -671,3 +676,3 @@ | ||
detailsOpened: | ||
(this._rowDetailsTemplate || this.rowDetailsRenderer) && this._isDetailsOpened(row._item) | ||
!!(this._rowDetailsTemplate || this.rowDetailsRenderer) && this._isDetailsOpened(row._item) | ||
}; | ||
@@ -674,0 +679,0 @@ } |
import './vaadin-grid-column-group.js'; | ||
import './vaadin-grid-column.js'; | ||
import './vaadin-grid-filter.js'; | ||
import './vaadin-grid-filter-column.js'; | ||
import './vaadin-grid-selection-column.js'; | ||
@@ -5,0 +6,0 @@ import './vaadin-grid-sorter.js'; |
import './vaadin-grid-column-group.js'; | ||
import './vaadin-grid-column.js'; | ||
import './vaadin-grid-filter.js'; | ||
import './vaadin-grid-filter-column.js'; | ||
import './vaadin-grid-selection-column.js'; | ||
@@ -5,0 +6,0 @@ import './vaadin-grid-sorter.js'; |
246786
1.26%63
6.78%6487
1.33%152
-3.18%