Fixed #6994 - DataTable: Frozen Column with Basic Filtering

pull/7048/head
tugcekucukoglu 2025-01-06 12:31:56 +03:00
parent 1536d128ac
commit 699c248538
3 changed files with 216 additions and 53 deletions

View File

@ -0,0 +1,190 @@
<template>
<th
v-if="!columnProp('hidden') && (rowGroupMode !== 'subheader' || groupRowsBy !== columnProp('field'))"
:style="getFilterColumnHeaderStyle"
:class="getFilterColumnHeaderClass"
v-bind="{ ...getColumnPT('root'), ...getColumnPT('headerCell') }"
:data-p-frozen-column="columnProp('frozen')"
>
<DTHeaderCheckbox v-if="columnProp('selectionMode') === 'multiple'" :checked="allRowsSelected" :disabled="empty" @change="$emit('checkbox-change', $event)" :column="column" :unstyled="unstyled" :pt="pt" />
<DTColumnFilter
v-if="column.children && column.children.filter"
:field="columnProp('filterField') || columnProp('field')"
:type="columnProp('dataType')"
display="row"
:showMenu="columnProp('showFilterMenu')"
:filterElement="column.children && column.children.filter"
:filterHeaderTemplate="column.children && column.children.filterheader"
:filterFooterTemplate="column.children && column.children.filterfooter"
:filterClearTemplate="column.children && column.children.filterclear"
:filterApplyTemplate="column.children && column.children.filterapply"
:filterIconTemplate="column.children && column.children.filtericon"
:filterAddIconTemplate="column.children && column.children.filteraddicon"
:filterRemoveIconTemplate="column.children && column.children.filterremoveicon"
:filterClearIconTemplate="column.children && column.children.filterclearicon"
:filters="filters"
:filtersStore="filtersStore"
:filterInputProps="filterInputProps"
:filterButtonProps="filterButtonProps"
@filter-change="$emit('filter-change', $event)"
@filter-apply="$emit('filter-apply')"
:filterMenuStyle="columnProp('filterMenuStyle')"
:filterMenuClass="columnProp('filterMenuClass')"
:showOperator="columnProp('showFilterOperator')"
:showClearButton="columnProp('showClearButton')"
:showApplyButton="columnProp('showApplyButton')"
:showMatchModes="columnProp('showFilterMatchModes')"
:showAddButton="columnProp('showAddButton')"
:matchModeOptions="columnProp('filterMatchModeOptions')"
:maxConstraints="columnProp('maxConstraints')"
@operator-change="$emit('operator-change', $event)"
@matchmode-change="$emit('matchmode-change', $event)"
@constraint-add="$emit('constraint-add', $event)"
@constraint-remove="$emit('constraint-remove', $event)"
@apply-click="$emit('apply-click', $event)"
:column="column"
:unstyled="unstyled"
:pt="pt"
/>
</th>
</template>
<script>
import { getNextElementSibling, getOuterWidth, getPreviousElementSibling } from '@primeuix/utils/dom';
import BaseComponent from '@primevue/core/basecomponent';
import { getVNodeProp } from '@primevue/core/utils';
import { mergeProps } from 'vue';
import ColumnFilter from './ColumnFilter.vue';
import HeaderCheckbox from './HeaderCheckbox.vue';
export default {
name: 'FilterHeaderCell',
hostName: 'DataTable',
extends: BaseComponent,
emits: ['checkbox-change', 'filter-change', 'filter-apply', 'operator-change', 'matchmode-change', 'constraint-add', 'constraint-remove', 'apply-click'],
props: {
column: {
type: Object,
default: null
},
index: {
type: Number,
default: null
},
allRowsSelected: {
type: Boolean,
default: false
},
empty: {
type: Boolean,
default: false
},
display: {
type: String,
default: 'row'
},
filters: {
type: Object,
default: null
},
filtersStore: {
type: Object,
default: null
},
rowGroupMode: {
type: String,
default: null
},
groupRowsBy: {
type: [Array, String, Function],
default: null
},
filterInputProps: {
type: null,
default: null
},
filterButtonProps: {
type: null,
default: null
}
},
data() {
return {
styleObject: {}
};
},
mounted() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
updated() {
if (this.columnProp('frozen')) {
this.updateStickyPosition();
}
},
methods: {
columnProp(prop) {
return getVNodeProp(this.column, prop);
},
getColumnPT(key) {
if (!this.column) return null;
const columnMetaData = {
props: this.column.props,
parent: {
instance: this,
props: this.$props,
state: this.$data
},
context: {
index: this.index
}
};
return mergeProps(this.ptm(`column.${key}`, { column: columnMetaData }), this.ptm(`column.${key}`, columnMetaData), this.ptmo(this.getColumnProp(), key, columnMetaData));
},
getColumnProp() {
return this.column.props && this.column.props.pt ? this.column.props.pt : undefined; //@todo
},
updateStickyPosition() {
if (this.columnProp('frozen')) {
let align = this.columnProp('alignFrozen');
if (align === 'right') {
let pos = 0;
let next = getNextElementSibling(this.$el, '[data-p-frozen-column="true"]');
if (next) {
pos = getOuterWidth(next) + parseFloat(next.style['inset-inline-end'] || 0);
}
this.styleObject.insetInlineEnd = pos + 'px';
} else {
console.log(getPreviousElementSibling(this.$el, '[data-p-frozen-column="true"]'));
let pos = 0;
let prev = getPreviousElementSibling(this.$el, '[data-p-frozen-column="true"]');
if (prev) {
pos = getOuterWidth(prev) + parseFloat(prev.style['inset-inline-start'] || 0);
}
this.styleObject.insetInlineStart = pos + 'px';
}
}
}
},
computed: {
getFilterColumnHeaderClass() {
return [this.cx('headerCell', { column: this.column }), this.columnProp('filterHeaderClass'), this.columnProp('class')];
},
getFilterColumnHeaderStyle() {
return this.columnProp('frozen') ? [this.columnProp('filterHeaderStyle'), this.columnProp('style'), this.styleObject] : [this.columnProp('filterHeaderStyle'), this.columnProp('style')];
}
},
components: {
DTHeaderCheckbox: HeaderCheckbox,
DTColumnFilter: ColumnFilter
}
};
</script>

View File

@ -79,53 +79,28 @@
</template>
<tr v-if="filterDisplay === 'row'" role="row" v-bind="ptm('headerRow')">
<template v-for="(col, i) of columns" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || i">
<th
<DTFilterHeaderCell
v-if="!columnProp(col, 'hidden') && (rowGroupMode !== 'subheader' || groupRowsBy !== columnProp(col, 'field'))"
:style="getFilterColumnHeaderStyle(col)"
:class="getFilterColumnHeaderClass(col)"
v-bind="{ ...getColumnPT(col, 'root', i), ...getColumnPT(col, 'headerCell', i) }"
>
<DTHeaderCheckbox v-if="columnProp(col, 'selectionMode') === 'multiple'" :checked="allRowsSelected" :disabled="empty" @change="$emit('checkbox-change', $event)" :column="col" :unstyled="unstyled" :pt="pt" />
<DTColumnFilter
v-if="col.children && col.children.filter"
:field="columnProp(col, 'filterField') || columnProp(col, 'field')"
:type="columnProp(col, 'dataType')"
display="row"
:showMenu="columnProp(col, 'showFilterMenu')"
:filterElement="col.children && col.children.filter"
:filterHeaderTemplate="col.children && col.children.filterheader"
:filterFooterTemplate="col.children && col.children.filterfooter"
:filterClearTemplate="col.children && col.children.filterclear"
:filterApplyTemplate="col.children && col.children.filterapply"
:filterIconTemplate="col.children && col.children.filtericon"
:filterAddIconTemplate="col.children && col.children.filteraddicon"
:filterRemoveIconTemplate="col.children && col.children.filterremoveicon"
:filterClearIconTemplate="col.children && col.children.filterclearicon"
:filters="filters"
:filtersStore="filtersStore"
:filterInputProps="filterInputProps"
:filterButtonProps="filterButtonProps"
@filter-change="$emit('filter-change', $event)"
@filter-apply="$emit('filter-apply')"
:filterMenuStyle="columnProp(col, 'filterMenuStyle')"
:filterMenuClass="columnProp(col, 'filterMenuClass')"
:showOperator="columnProp(col, 'showFilterOperator')"
:showClearButton="columnProp(col, 'showClearButton')"
:showApplyButton="columnProp(col, 'showApplyButton')"
:showMatchModes="columnProp(col, 'showFilterMatchModes')"
:showAddButton="columnProp(col, 'showAddButton')"
:matchModeOptions="columnProp(col, 'filterMatchModeOptions')"
:maxConstraints="columnProp(col, 'maxConstraints')"
@operator-change="$emit('operator-change', $event)"
@matchmode-change="$emit('matchmode-change', $event)"
@constraint-add="$emit('constraint-add', $event)"
@constraint-remove="$emit('constraint-remove', $event)"
@apply-click="$emit('apply-click', $event)"
:column="col"
:unstyled="unstyled"
:pt="pt"
/>
</th>
:column="col"
:index="i"
:allRowsSelected="allRowsSelected"
:empty="empty"
display="row"
:filters="filters"
:filtersStore="filtersStore"
:filterInputProps="filterInputProps"
:filterButtonProps="filterButtonProps"
@filter-change="$emit('filter-change', $event)"
@filter-apply="$emit('filter-apply')"
@operator-change="$emit('operator-change', $event)"
@matchmode-change="$emit('matchmode-change', $event)"
@constraint-add="$emit('constraint-add', $event)"
@constraint-remove="$emit('constraint-remove', $event)"
@apply-click="$emit('apply-click', $event)"
@change="$emit('checkbox-change', $event)"
:unstyled="unstyled"
:pt="pt"
/>
</template>
</tr>
</thead>
@ -135,9 +110,8 @@
import BaseComponent from '@primevue/core/basecomponent';
import { HelperSet, getVNodeProp } from '@primevue/core/utils';
import { mergeProps } from 'vue';
import ColumnFilter from './ColumnFilter.vue';
import FilterHeaderCell from './FilterHeaderCell.vue';
import HeaderCell from './HeaderCell.vue';
import HeaderCheckbox from './HeaderCheckbox.vue';
export default {
name: 'TableHeader',
@ -338,8 +312,7 @@ export default {
},
components: {
DTHeaderCell: HeaderCell,
DTHeaderCheckbox: HeaderCheckbox,
DTColumnFilter: ColumnFilter
DTFilterHeaderCell: FilterHeaderCell
}
};
</script>

View File

@ -620,11 +620,11 @@ const classes = {
],
thead: 'p-datatable-thead',
headerCell: ({ instance, props, column }) =>
column && !instance.columnProp(column, 'hidden') && (props.rowGroupMode !== 'subheader' || props.groupRowsBy !== instance.columnProp(column, 'field'))
column && !instance.columnProp('hidden') && (props.rowGroupMode !== 'subheader' || props.groupRowsBy !== instance.columnProp(column, 'field'))
? [
'p-datatable-header-cell',
{
'p-datatable-frozen-column': instance.columnProp(column, 'frozen')
'p-datatable-frozen-column': instance.columnProp('frozen')
}
]
: [
@ -653,7 +653,7 @@ const classes = {
filterElementContainer: 'p-datatable-filter-element-container',
pcColumnFilterButton: 'p-datatable-column-filter-button',
pcColumnFilterClearButton: 'p-datatable-column-filter-clear-button',
filterOverlay: ({ instance, props }) => [
filterOverlay: ({ props }) => [
'p-datatable-filter-overlay p-component',
{
'p-datatable-filter-overlay-popover': props.display === 'menu'