diff --git a/src/components/datatable/DataTable.d.ts b/src/components/datatable/DataTable.d.ts
index e5d1579ee..345059340 100644
--- a/src/components/datatable/DataTable.d.ts
+++ b/src/components/datatable/DataTable.d.ts
@@ -47,6 +47,13 @@ export declare class DataTable extends Vue {
editMode?: string;
editingRows?: any[];
rowClass?: any;
+ scrollable?: boolean;
+ scrollHeight?: string;
+ frozenValue?: any[];
+ frozenWidth?: string;
+ virtualScroll?: boolean;
+ virtualRowHeight?: string;
+ virtualScrollDelay?: number;
$emit(eventName: 'page', event: Event): this;
$emit(eventName: 'sort', event: Event): this;
$emit(eventName: 'filter', event: Event): this;
diff --git a/src/components/datatable/DataTable.vue b/src/components/datatable/DataTable.vue
index a769f8bbe..43163da22 100644
--- a/src/components/datatable/DataTable.vue
+++ b/src/components/datatable/DataTable.vue
@@ -340,11 +340,11 @@ export default {
},
virtualRowHeight: {
type: Number,
- default: null
+ default: 28
},
virtualScrollDelay: {
type: Number,
- default: 159
+ default: 150
}
},
data() {
diff --git a/src/views/datatable/DataTableDoc.vue b/src/views/datatable/DataTableDoc.vue
index 682d624ec..9bf055c1b 100644
--- a/src/views/datatable/DataTableDoc.vue
+++ b/src/views/datatable/DataTableDoc.vue
@@ -262,6 +262,18 @@ export default {
false |
When enabled, column displays row editor controls. |
+
+ rowEditor |
+ boolean |
+ false |
+ When enabled, column displays row editor controls. |
+
+
+ frozen |
+ boolean |
+ false |
+ Whether the column is fixed in horizontal scrolling. |
+
@@ -550,6 +562,149 @@ data() {
<Column field="color" header="Color"></Column>
</DataTable>
+
+
+ Scrolling
+ DataTable supports both horizontal and vertical scrolling as well as frozen columns and rows. Scrollable DataTable is enabled using scrollable property and scrollHeight to define the viewport height.
+
+
+<DataTable :value="cars" :scrollable="true" scrollHeight="200px">
+ <Column field="vin" header="Vin"></Column>
+ <Column field="year" header="Year"></Column>
+ <Column field="brand" header="Brand"></Column>
+ <Column field="color" header="Color"></Column>
+</DataTable>
+
+
+
+ Horizontal Scrolling requires a width of DataTable to be defined and explicit widths on columns.
+
+
+<DataTable :value="cars" :scrollable="true" scrollHeight="200px" style="width: 600px">
+ <Column field="vin" header="Vin" headerStyle="width: 250px" columnKey="vin_1"></Column>
+ <Column field="year" header="Year" headerStyle="width: 250px" columnKey="year_1"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 250px" columnKey="brand_1"></Column>
+ <Column field="color" header="Color" headerStyle="width: 250px" columnKey="color_1"></Column>
+ <Column field="vin" header="Vin" headerStyle="width: 250px" columnKey="vin_2"></Column>
+ <Column field="year" header="Year" headerStyle="width: 250px" columnKey="year_2"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 250px" columnKey="brand_2"></Column>
+ <Column field="color" header="Color" headerStyle="width: 250px" columnKey="color_2"></Column>
+</DataTable>
+
+
+
+ Certain columns can be frozen by using the frozen property of the column component. Widths of the frozen section is specified by the frozenWidth property.
+
+
+<DataTable :value="cars" :scrollable="true" scrollHeight="200px" frozenWidth="300px" :loading="loading">
+ <Column field="vin" header="Vin" headerStyle="width: 300px" columnKey="vin_1" :frozen="true">
+ <template #body="slotProps">
+ <span style="font-weight: bold">{{slotProps.data.vin}}</span>
+ </template>
+ </Column>
+ <Column field="year" header="Year" headerStyle="width: 300px" columnKey="year_1"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 300px" columnKey="brand_1"></Column>
+ <Column field="color" header="Color" headerStyle="width: 300px" columnKey="color_1"></Column>
+ <Column field="year" header="Year" headerStyle="width: 300px" columnKey="year_2"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 300px" columnKey="brand_2"></Column>
+ <Column field="color" header="Color" headerStyle="width: 300px" columnKey="color_2"></Column>
+ <Column field="year" header="Year" headerStyle="width: 300px" columnKey="year_3"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 300px" columnKey="brand_3"></Column>
+ <Column field="color" header="Color" headerStyle="width: 300px" columnKey="color_3"></Column>
+</DataTable>
+
+
+
+ Note that frozen columns are enabled, frozen and scrollable cells may have content with varying height which leads to misalignment. Provide fixed height to cells to avoid alignment issues.
+
+
+<DataTable :value="cars" :scrollable="true" scrollHeight="200px" frozenWidth="300px" :loading="loading">
+ <Column field="vin" header="Vin" headerStyle="width: 300px" bodyStyle="height: 25px" columnKey="vin" :frozen="true">
+ <template #body="slotProps">
+ <span style="font-weight: bold">{{slotProps.data.vin}}</span>
+ </template>
+ </Column>
+ <Column field="year" header="Year" headerStyle="width: 300px" bodyStyle="height: 25px" columnKey="year"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 300px" bodyStyle="height: 25px" columnKey="brand"></Column>
+ <Column field="color" header="Color" headerStyle="width: 300px" bodyStyle="height: 25px" columnKey="color"></Column>
+</DataTable>
+
+
+
+ One or more rows can be displayed as fixed using the frozenValue property.
+
+
+<DataTable :value="cars" :frozenValue="frozenCars" :scrollable="true" scrollHeight="200px" :loading="loading">
+ <Column field="vin" header="Vin"></Column>
+ <Column field="year" header="Year"></Column>
+ <Column field="brand" header="Brand"></Column>
+ <Column field="color" header="Color"></Column>
+</DataTable>
+
+
+
+ When using frozen columns with column grouping, use frozenheadergroup and frozenfootergroup types to define grouping for the frozen section.
+
+ Virtual scrolling is enabled using virtualScroll and onVirtualScroll properties combined with lazy loading so that data is loaded on the fly during scrolling.
+ For smooth scrolling twice the amount of rows property is loaded on a lazy load event. In addition, to avoid performance problems row height is not calculated automatically and
+ should be provided using virtualRowHeight property which defaults to 28px. View the scrolling demo for a sample in-memory implementation.
+
+
+
+<DataTable :value="lazyCars" :scrollable="true" scrollHeight="200px" :lazy="true" :rows="20"
+ :virtualScroll="true" :virtualRowHeight="30" @virtual-scroll="onVirtualScroll" :totalRecords="lazyTotalRecords">
+ <Column field="vin" header="Vin">
+ <template #loading>
+ <span class="loading-text"></span>
+ </template>
+ </Column>
+ <Column field="year" header="Year">
+ <template #loading>
+ <span class="loading-text"></span>
+ </template>
+ </Column>
+ <Column field="brand" header="Brand">
+ <template #loading>
+ <span class="loading-text"></span>
+ </template>
+ </Column>
+ <Column field="color" header="Color">
+ <template #loading>
+ <span class="loading-text"></span>
+ </template>
+ </Column>
+</DataTable>
+
+
+
+
+import CarService from '../../service/CarService';
+
+export default {
+ data() {
+ return {
+ lazyCars: null,
+ lazyTotalRecords: 0
+ }
+ },
+ carService: null,
+ mounted() {
+ this.lazyCars = this.loadChunk(0, 40);
+ this.lazyTotalRecords = //retrieve logical number of rows from a datasource;
+ },
+ methods: {
+ loadChunk(index, length) {
+ //return data from a datasource between [index, index + length];
+ },
+ onVirtualScroll(event) {
+ //last chunk
+ if (event.first === (this.lazyTotalRecords - 20))
+ this.lazyCars = this.loadChunk(event.first, 20)
+ else
+ this.lazyCars = this.loadChunk(event.first, event.rows)
+ }
+ }
+}
Lazy Loading
@@ -1697,6 +1852,48 @@ export default {
null |
A function that takes the row data and returns a string to apply a particular class for the row. |
+
+ scrollable |
+ boolean |
+ false |
+ When specified, enables horizontal and/or vertical scrolling. |
+
+
+ scrollHeight |
+ string |
+ null |
+ Height of the scroll viewport. |
+
+
+ virtualScroll |
+ boolean |
+ false |
+ Whether the data should be loaded on demand during scroll. |
+
+
+ virtualScrollDelay |
+ number |
+ 150 |
+ Delay in virtual scroll before doing a call to lazy load. |
+
+
+ virtualRowHeight |
+ number |
+ 28 |
+ Height of a row to use in calculations of virtual scrolling. |
+
+
+ frozenWidth |
+ string |
+ null |
+ Width of the frozen part in scrollable DataTable. |
+
+
+ frozenValue |
+ array |
+ null |
+ Items of the frozen part in scrollable DataTable. |
+
@@ -1849,6 +2046,12 @@ export default {
event.index: Index of the row data to edit.
Callback to invoke when row edit is cancelled. |
+
+ virtual-scroll |
+ event.first: Index of the first row.
+ event.rows: Rows per page. |
+ Callback to invoke during virtual scrolling. |
+
diff --git a/src/views/datatable/DataTableScrollDemo.vue b/src/views/datatable/DataTableScrollDemo.vue
index fee25940b..5038acd34 100644
--- a/src/views/datatable/DataTableScrollDemo.vue
+++ b/src/views/datatable/DataTableScrollDemo.vue
@@ -87,11 +87,195 @@
+<h3>Vertical</h3>
+<DataTable :value="cars" :scrollable="true" scrollHeight="200px" :loading="loading">
+ <Column field="vin" header="Vin"></Column>
+ <Column field="year" header="Year"></Column>
+ <Column field="brand" header="Brand"></Column>
+ <Column field="color" header="Color"></Column>
+</DataTable>
+
+<h3>Virtual Scroll</h3>
+<DataTable :value="lazyCars" :scrollable="true" scrollHeight="200px" :lazy="true" :rows="20" :loading="loading"
+ :virtualScroll="true" :virtualRowHeight="30" @virtual-scroll="onVirtualScroll" :totalRecords="lazyTotalRecords">
+ <Column field="vin" header="Vin">
+ <template #loading>
+ <span class="loading-text"></span>
+ </template>
+ </Column>
+ <Column field="year" header="Year">
+ <template #loading>
+ <span class="loading-text"></span>
+ </template>
+ </Column>
+ <Column field="brand" header="Brand">
+ <template #loading>
+ <span class="loading-text"></span>
+ </template>
+ </Column>
+ <Column field="color" header="Color">
+ <template #loading>
+ <span class="loading-text"></span>
+ </template>
+ </Column>
+</DataTable>
+
+<h3>Horizontal and Vertical</h3>
+<DataTable :value="cars" :scrollable="true" scrollHeight="200px" style="width: 600px" :loading="loading">
+ <Column field="vin" header="Vin" headerStyle="width: 250px" columnKey="vin_1"></Column>
+ <Column field="year" header="Year" headerStyle="width: 250px" columnKey="year_1"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 250px" columnKey="brand_1"></Column>
+ <Column field="color" header="Color" headerStyle="width: 250px" columnKey="color_1"></Column>
+ <Column field="vin" header="Vin" headerStyle="width: 250px" columnKey="vin_2"></Column>
+ <Column field="year" header="Year" headerStyle="width: 250px" columnKey="year_2"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 250px" columnKey="brand_2"></Column>
+ <Column field="color" header="Color" headerStyle="width: 250px" columnKey="color_2"></Column>
+</DataTable>
+
+<h3>Frozen Rows</h3>
+<DataTable :value="cars" :frozenValue="frozenCars" :scrollable="true" scrollHeight="200px" :loading="loading">
+ <Column field="vin" header="Vin"></Column>
+ <Column field="year" header="Year"></Column>
+ <Column field="brand" header="Brand"></Column>
+ <Column field="color" header="Color"></Column>
+</DataTable>
+
+<h3>Frozen Columns</h3>
+<DataTable :value="cars" :scrollable="true" scrollHeight="200px" frozenWidth="300px" :loading="loading">
+ <Column field="vin" header="Vin" headerStyle="width: 300px" columnKey="vin_1" :frozen="true">
+ <template #body="slotProps">
+ <span style="font-weight: bold">{{slotProps.data.vin}}</span>
+ </template>
+ </Column>
+ <Column field="year" header="Year" headerStyle="width: 300px" columnKey="year_1"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 300px" columnKey="brand_1"></Column>
+ <Column field="color" header="Color" headerStyle="width: 300px" columnKey="color_1"></Column>
+ <Column field="year" header="Year" headerStyle="width: 300px" columnKey="year_2"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 300px" columnKey="brand_2"></Column>
+ <Column field="color" header="Color" headerStyle="width: 300px" columnKey="color_2"></Column>
+ <Column field="year" header="Year" headerStyle="width: 300px" columnKey="year_3"></Column>
+ <Column field="brand" header="Brand" headerStyle="width: 300px" columnKey="brand_3"></Column>
+ <Column field="color" header="Color" headerStyle="width: 300px" columnKey="color_3"></Column>
+</DataTable>
+import CarService from '../../service/CarService';
+export default {
+ data() {
+ return {
+ cars: null,
+ frozenCars: null,
+ lazyCars: null,
+ lazyTotalRecords: 0,
+ loading: false
+ }
+ },
+ carService: null,
+ inmemoryData: null,
+ created() {
+ this.carService = new CarService();
+
+ this.inmemoryData = [
+ {"brand": "VW", "year": 2012, "color": "Orange"},
+ {"brand": "Audi", "year": 2011, "color": "Black"},
+ {"brand": "Renault", "year": 2005, "color": "Gray"},
+ {"brand": "BMW", "year": 2003, "color": "Blue"},
+ {"brand": "Mercedes", "year": 1995, "color": "Orange"},
+ {"brand": "Volvo", "year": 2005, "color": "Black"},
+ {"brand": "Honda", "year": 2012, "color": "Yellow"},
+ {"brand": "Jaguar", "year": 2013, "color": "Orange"},
+ {"brand": "Ford", "year": 2000, "color": "Black"},
+ {"brand": "Fiat", "year": 2013, "color": "Red"},
+ {"brand": "VW", "year": 2012, "color": "Orange"},
+ {"brand": "Audi", "year": 2011, "color": "Black"},
+ {"brand": "Renault", "year": 2005, "color": "Gray"},
+ {"brand": "BMW", "year": 2003, "color": "Blue"},
+ {"brand": "Mercedes", "year": 1995, "color": "Orange"},
+ {"brand": "Volvo", "year": 2005, "color": "Black"},
+ {"brand": "Honda", "year": 2012, "color": "Yellow"},
+ {"brand": "Jaguar", "year": 2013, "color": "Orange"},
+ {"brand": "Ford", "year": 2000, "color": "Black"},
+ {"brand": "Fiat", "year": 2013, "color": "Red"},
+ {"brand": "VW", "year": 2012, "color": "Orange"},
+ {"brand": "Audi", "year": 2011, "color": "Black"},
+ {"brand": "Renault", "year": 2005, "color": "Gray"},
+ {"brand": "BMW", "year": 2003, "color": "Blue"},
+ {"brand": "Mercedes", "year": 1995, "color": "Orange"},
+ {"brand": "Volvo", "year": 2005, "color": "Black"},
+ {"brand": "Honda", "year": 2012, "color": "Yellow"},
+ {"brand": "Jaguar", "year": 2013, "color": "Orange"},
+ {"brand": "Ford", "year": 2000, "color": "Black"},
+ {"brand": "Fiat", "year": 2013, "color": "Red"},
+ {"brand": "VW", "year": 2012, "color": "Orange"},
+ {"brand": "Audi", "year": 2011, "color": "Black"},
+ {"brand": "Renault", "year": 2005, "color": "Gray"},
+ {"brand": "BMW", "year": 2003, "color": "Blue"},
+ {"brand": "Mercedes", "year": 1995, "color": "Orange"},
+ {"brand": "Volvo", "year": 2005, "color": "Black"},
+ {"brand": "Honda", "year": 2012, "color": "Yellow"},
+ {"brand": "Jaguar", "year": 2013, "color": "Orange"},
+ {"brand": "Ford", "year": 2000, "color": "Black"},
+ {"brand": "Fiat", "year": 2013, "color": "Red"}
+ ];
+ },
+ mounted() {
+ this.loading = true;
+
+ setTimeout(() => {
+ this.carService.getCarsLarge().then(data => {
+ this.cars = data
+ this.loading = false;
+ });
+ }, 150);
+
+ this.frozenCars = [
+ {brand: "BMW", year: 2013, color: "Grey", vin: "fh2uf23"},
+ {brand: "Chevrolet", year: 2011, color: "Black", vin: "4525g23"}
+ ];
+
+ setTimeout(() => {
+ this.lazyCars = this.loadChunk(0, 40);
+ this.lazyTotalRecords = 250000;
+ }, 250);
+ },
+ methods: {
+ loadChunk(index, length) {
+ let chunk = [];
+ for (let i = 0; i < length; i++) {
+ chunk[i] = {...this.inmemoryData[i], ...{vin: (index + i)}};
+ }
+
+ return chunk;
+ },
+ onVirtualScroll(event) {
+ /*
+ For demo purposes keep loading the same dataset,
+ in a real production application, this data should come from server by building the query with LazyLoadEvent options
+ */
+ setTimeout(() => {
+ //last chunk
+ if (event.first === 249980)
+ this.lazyCars = this.loadChunk(event.first, 20)
+ else
+ this.lazyCars = this.loadChunk(event.first, event.rows)
+ }, 250);
+ }
+ }
+}
+
+
+
+.loading-text {
+ display: block;
+ background-color: #f1f1f1;
+ min-height: 19px;
+ animation: pulse 1s infinite ease-in-out;
+ text-indent: -99999px;
+ overflow: hidden;
+}