Fixed #1841 - DataTable component does not work correctly "Checkbox selection" together with "lazy"
parent
e08fd2d1d0
commit
229ba94153
|
@ -82,7 +82,7 @@ import TableFooter from './TableFooter.vue';
|
||||||
export default {
|
export default {
|
||||||
name: 'DataTable',
|
name: 'DataTable',
|
||||||
emits: ['value-change', 'update:first', 'update:rows', 'page', 'update:sortField', 'update:sortOrder', 'update:multiSortMeta', 'sort', 'filter', 'row-click', 'row-dblclick',
|
emits: ['value-change', 'update:first', 'update:rows', 'page', 'update:sortField', 'update:sortOrder', 'update:multiSortMeta', 'sort', 'filter', 'row-click', 'row-dblclick',
|
||||||
'update:selection', 'row-select', 'row-unselect', 'update:contextMenuSelection', 'row-contextmenu', 'row-unselect-all', 'row-select-all',
|
'update:selection', 'row-select', 'row-unselect', 'update:contextMenuSelection', 'row-contextmenu', 'row-unselect-all', 'row-select-all', 'select-all-change',
|
||||||
'column-resize-end', 'column-reorder', 'row-reorder', 'update:expandedRows', 'row-collapse', 'row-expand',
|
'column-resize-end', 'column-reorder', 'row-reorder', 'update:expandedRows', 'row-collapse', 'row-expand',
|
||||||
'update:expandedRowGroups', 'rowgroup-collapse', 'rowgroup-expand', 'update:filters', 'state-restore', 'state-save',
|
'update:expandedRowGroups', 'rowgroup-collapse', 'rowgroup-expand', 'update:filters', 'state-restore', 'state-save',
|
||||||
'cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel', 'update:editingRows', 'row-edit-init', 'row-edit-save', 'row-edit-cancel'],
|
'cell-edit-init', 'cell-edit-complete', 'cell-edit-cancel', 'update:editingRows', 'row-edit-init', 'row-edit-save', 'row-edit-cancel'],
|
||||||
|
@ -211,6 +211,10 @@ export default {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
selectAll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
rowHover: {
|
rowHover: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
@ -883,15 +887,24 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleRowsWithCheckbox(event) {
|
toggleRowsWithCheckbox(event) {
|
||||||
const processedData = this.processedData;
|
if (this.selectAll !== null) {
|
||||||
const checked = this.allRowsSelected;
|
this.$emit('select-all-change', event);
|
||||||
const _selection = checked ? [] : (this.frozenValue ? [...this.frozenValue, ...processedData]: processedData);
|
}
|
||||||
this.$emit('update:selection', _selection);
|
else {
|
||||||
|
const { originalEvent, checked } = event;
|
||||||
|
let _selection = [];
|
||||||
|
|
||||||
if (checked)
|
if (checked) {
|
||||||
this.$emit('row-unselect-all', {originalEvent: event});
|
_selection = this.frozenValue ? [...this.frozenValue, ...this.processedData] : this.processedData;
|
||||||
else
|
this.$emit('row-select-all', {originalEvent, data: _selection});
|
||||||
this.$emit('row-select-all', {originalEvent: event, data: _selection});
|
}
|
||||||
|
else {
|
||||||
|
this.$emit('row-unselect-all', {originalEvent});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$emit('update:selection', _selection);
|
||||||
|
|
||||||
|
}
|
||||||
},
|
},
|
||||||
isSingleSelectionMode() {
|
isSingleSelectionMode() {
|
||||||
return this.selectionMode === 'single';
|
return this.selectionMode === 'single';
|
||||||
|
@ -1887,9 +1900,13 @@ export default {
|
||||||
return ['p-datatable-loading-icon pi-spin', this.loadingIcon];
|
return ['p-datatable-loading-icon pi-spin', this.loadingIcon];
|
||||||
},
|
},
|
||||||
allRowsSelected() {
|
allRowsSelected() {
|
||||||
const val = this.frozenValue ? [...this.frozenValue, ...this.processedData]: this.processedData;
|
if (this.selectAll !== null) {
|
||||||
const length = this.lazy ? this.totalRecords : (val ? val.length : 0);
|
return this.selectAll;
|
||||||
return (val && length > 0 && this.selection && this.selection.length > 0 && this.selection.length === length);
|
}
|
||||||
|
else {
|
||||||
|
const val = this.frozenValue ? [...this.frozenValue, ...this.processedData] : this.processedData;
|
||||||
|
return val && this.selection && Array.isArray(this.selection) && val.every(v => this.selection.some(s => this.equals(s, v)));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
attributeSelector() {
|
attributeSelector() {
|
||||||
return UniqueComponentId();
|
return UniqueComponentId();
|
||||||
|
|
|
@ -24,7 +24,10 @@ export default {
|
||||||
onClick(event) {
|
onClick(event) {
|
||||||
if (!this.$attrs.disabled) {
|
if (!this.$attrs.disabled) {
|
||||||
this.focused = true;
|
this.focused = true;
|
||||||
this.$emit('change', event);
|
this.$emit('change', {
|
||||||
|
originalEvent: event,
|
||||||
|
checked: !this.checked
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onFocus() {
|
onFocus() {
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default class CustomerService {
|
||||||
}
|
}
|
||||||
|
|
||||||
getCustomers(params) {
|
getCustomers(params) {
|
||||||
const queryParams = Object.keys(params).map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])).join('&');
|
const queryParams = params ? Object.keys(params).map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])).join('&') : '';
|
||||||
return fetch('https://www.primefaces.org/data/customers?' + queryParams).then(res => res.json())
|
return fetch('https://www.primefaces.org/data/customers?' + queryParams).then(res => res.json())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
|
|
||||||
<div class="content-section implementation">
|
<div class="content-section implementation">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<DataTable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt"
|
<DataTable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt" dataKey="id"
|
||||||
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
|
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
|
||||||
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll" >
|
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll"
|
||||||
|
v-model:selection="selectedCustomers" :selectAll="selectAll" @select-all-change="onSelectAllChange" @row-select="onRowSelect" @row-unselect="onRowUnselect">
|
||||||
|
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
|
||||||
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
|
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
|
||||||
<template #filter="{filterModel,filterCallback}">
|
<template #filter="{filterModel,filterCallback}">
|
||||||
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"/>
|
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"/>
|
||||||
|
@ -53,6 +55,8 @@ export default {
|
||||||
loading: false,
|
loading: false,
|
||||||
totalRecords: 0,
|
totalRecords: 0,
|
||||||
customers: null,
|
customers: null,
|
||||||
|
selectedCustomers: null,
|
||||||
|
selectAll: false,
|
||||||
filters: {
|
filters: {
|
||||||
'name': {value: '', matchMode: 'contains'},
|
'name': {value: '', matchMode: 'contains'},
|
||||||
'country.name': {value: '', matchMode: 'contains'},
|
'country.name': {value: '', matchMode: 'contains'},
|
||||||
|
@ -72,9 +76,11 @@ export default {
|
||||||
content: `
|
content: `
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<DataTable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt"
|
<DataTable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt" dataKey="id"
|
||||||
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
|
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
|
||||||
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll">
|
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll"
|
||||||
|
v-model:selection="selectedCustomers" :selectAll="selectAll" @select-all-change="onSelectAllChange" @row-select="onRowSelect" @row-unselect="onRowUnselect">
|
||||||
|
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
|
||||||
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
|
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
|
||||||
<template #filter="{filterModel,filterCallback}">
|
<template #filter="{filterModel,filterCallback}">
|
||||||
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"/>
|
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"/>
|
||||||
|
@ -108,6 +114,8 @@ export default {
|
||||||
loading: false,
|
loading: false,
|
||||||
totalRecords: 0,
|
totalRecords: 0,
|
||||||
customers: null,
|
customers: null,
|
||||||
|
selectedCustomers: null,
|
||||||
|
selectAll: false,
|
||||||
filters: {
|
filters: {
|
||||||
'name': {value: '', matchMode: 'contains'},
|
'name': {value: '', matchMode: 'contains'},
|
||||||
'country.name': {value: '', matchMode: 'contains'},
|
'country.name': {value: '', matchMode: 'contains'},
|
||||||
|
@ -166,6 +174,26 @@ export default {
|
||||||
onFilter() {
|
onFilter() {
|
||||||
this.lazyParams.filters = this.filters;
|
this.lazyParams.filters = this.filters;
|
||||||
this.loadLazyData();
|
this.loadLazyData();
|
||||||
|
},
|
||||||
|
onSelectAllChange(event) {
|
||||||
|
const selectAll = event.checked;
|
||||||
|
|
||||||
|
if (selectAll) {
|
||||||
|
this.customerService.getCustomers().then(data => {
|
||||||
|
this.selectAll = true;
|
||||||
|
this.selectedCustomers = data.customers;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.selectAll = false;
|
||||||
|
this.selectedCustomers = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRowSelect() {
|
||||||
|
this.selectAll = this.selectedCustomers.length === this.totalRecords
|
||||||
|
},
|
||||||
|
onRowUnselect() {
|
||||||
|
this.selectAll = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,9 +205,11 @@ export default {
|
||||||
content: `
|
content: `
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<DataTable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt"
|
<DataTable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt" dataKey="id"
|
||||||
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
|
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
|
||||||
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll">
|
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll"
|
||||||
|
v-model:selection="selectedCustomers" :selectAll="selectAll" @select-all-change="onSelectAllChange" @row-select="onRowSelect" @row-unselect="onRowUnselect">
|
||||||
|
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
|
||||||
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
|
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
|
||||||
<template #filter="{filterModel,filterCallback}">
|
<template #filter="{filterModel,filterCallback}">
|
||||||
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"/>
|
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"/>
|
||||||
|
@ -228,6 +258,8 @@ export default {
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const totalRecords = ref(0);
|
const totalRecords = ref(0);
|
||||||
const customers = ref();
|
const customers = ref();
|
||||||
|
const selectedCustomers = ref();
|
||||||
|
const selectAll = ref(false);
|
||||||
const customerService = ref(new CustomerService());
|
const customerService = ref(new CustomerService());
|
||||||
const filters = ref({
|
const filters = ref({
|
||||||
'name': {value: '', matchMode: 'contains'},
|
'name': {value: '', matchMode: 'contains'},
|
||||||
|
@ -269,8 +301,28 @@ export default {
|
||||||
lazyParams.value.filters = filters.value ;
|
lazyParams.value.filters = filters.value ;
|
||||||
loadLazyData();
|
loadLazyData();
|
||||||
}
|
}
|
||||||
|
const onSelectAllChange = (event) => {
|
||||||
|
const selectAll = event.checked;
|
||||||
|
|
||||||
return { dt, loading, totalRecords, customers, filters, lazyParams, columns, loadLazyData, onPage, onSort, onFilter }
|
if (selectAll) {
|
||||||
|
customerService.value.getCustomers().then(data => {
|
||||||
|
selectAll.value = true;
|
||||||
|
selectedCustomers.value = data.customers;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectAll.value = false;
|
||||||
|
selectedCustomers.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onRowSelect = () => {
|
||||||
|
selectAll.value = selectedCustomers.value.length === totalRecords.value;
|
||||||
|
}
|
||||||
|
const onRowUnselect = () => {
|
||||||
|
selectAll.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { dt, loading, totalRecords, customers, filters, lazyParams, columns, loadLazyData, onPage, onSort, onFilter, onSelectAllChange, onRowSelect, onRowUnselect }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<\\/script>
|
<\\/script>
|
||||||
|
@ -282,9 +334,11 @@ export default {
|
||||||
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
|
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
|
||||||
<script src="./CustomerService.js"><\\/script>`,
|
<script src="./CustomerService.js"><\\/script>`,
|
||||||
content: `<div id="app">
|
content: `<div id="app">
|
||||||
<p-datatable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt"
|
<p-datatable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt" dataKey="id"
|
||||||
:total-records="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filter-display="row"
|
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
|
||||||
:global-filter-fields="['name','country.name', 'company', 'representative.name']" responsive-layout="scroll">
|
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll"
|
||||||
|
v-model:selection="selectedCustomers" :selectAll="selectAll" @select-all-change="onSelectAllChange" @row-select="onRowSelect" @row-unselect="onRowUnselect">
|
||||||
|
<p-column selectionMode="multiple" headerStyle="width: 3em"></Column>
|
||||||
<p-column field="name" header="Name" filter-match-mode="startsWith" ref="name" :sortable="true">
|
<p-column field="name" header="Name" filter-match-mode="startsWith" ref="name" :sortable="true">
|
||||||
<template #filter="{filterModel,filterCallback}">
|
<template #filter="{filterModel,filterCallback}">
|
||||||
<p-inputtext type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"></p-inputtext>
|
<p-inputtext type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"></p-inputtext>
|
||||||
|
@ -331,6 +385,8 @@ export default {
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const totalRecords = ref(0);
|
const totalRecords = ref(0);
|
||||||
const customers = ref();
|
const customers = ref();
|
||||||
|
const selectedCustomers = ref();
|
||||||
|
const selectAll = ref(false);
|
||||||
const customerService = ref(new CustomerService());
|
const customerService = ref(new CustomerService());
|
||||||
const filters = ref({
|
const filters = ref({
|
||||||
'name': {value: '', matchMode: 'contains'},
|
'name': {value: '', matchMode: 'contains'},
|
||||||
|
@ -373,7 +429,28 @@ export default {
|
||||||
loadLazyData();
|
loadLazyData();
|
||||||
}
|
}
|
||||||
|
|
||||||
return { dt, loading, totalRecords, customers, filters, lazyParams, columns, loadLazyData, onPage, onSort, onFilter }
|
const onSelectAllChange = (event) => {
|
||||||
|
const selectAll = event.checked;
|
||||||
|
|
||||||
|
if (selectAll) {
|
||||||
|
customerService.value.getCustomers().then(data => {
|
||||||
|
selectAll.value = true;
|
||||||
|
selectedCustomers.value = data.customers;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectAll.value = false;
|
||||||
|
selectedCustomers.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onRowSelect = () => {
|
||||||
|
selectAll.value = selectedCustomers.value.length === totalRecords.value;
|
||||||
|
}
|
||||||
|
const onRowUnselect = () => {
|
||||||
|
selectAll.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { dt, loading, totalRecords, customers, filters, lazyParams, columns, loadLazyData, onPage, onSort, onFilter, onSelectAllChange, onRowSelect, onRowUnselect }
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
"p-datatable": primevue.datatable,
|
"p-datatable": primevue.datatable,
|
||||||
|
@ -431,6 +508,26 @@ export default {
|
||||||
onFilter() {
|
onFilter() {
|
||||||
this.lazyParams.filters = this.filters;
|
this.lazyParams.filters = this.filters;
|
||||||
this.loadLazyData();
|
this.loadLazyData();
|
||||||
|
},
|
||||||
|
onSelectAllChange(event) {
|
||||||
|
const selectAll = event.checked;
|
||||||
|
|
||||||
|
if (selectAll) {
|
||||||
|
this.customerService.getCustomers().then(data => {
|
||||||
|
this.selectAll = true;
|
||||||
|
this.selectedCustomers = data.customers;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.selectAll = false;
|
||||||
|
this.selectedCustomers = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRowSelect() {
|
||||||
|
this.selectAll = this.selectedCustomers.length === this.totalRecords
|
||||||
|
},
|
||||||
|
onRowUnselect() {
|
||||||
|
this.selectAll = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5>Checkbox</h5>
|
<h5>Checkbox</h5>
|
||||||
|
|
||||||
<DataTable :value="products" v-model:selection="selectedProducts3" dataKey="id" responsiveLayout="scroll" >
|
<DataTable :value="products" v-model:selection="selectedProducts3" dataKey="id" responsiveLayout="scroll">
|
||||||
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
|
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
|
||||||
<Column field="code" header="Code"></Column>
|
<Column field="code" header="Code"></Column>
|
||||||
<Column field="name" header="Name"></Column>
|
<Column field="name" header="Name"></Column>
|
||||||
|
|
Loading…
Reference in New Issue