feat: reusable ag grid
This commit is contained in:
@@ -5,15 +5,23 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
const showDeleteDialog = ref(false)
|
||||
const selectedRowData = ref(null)
|
||||
const deleteRowData = ref(null)
|
||||
const selectedRowNodeId = ref(null)
|
||||
const deleteRowNodeId = ref(null)
|
||||
|
||||
const getRowDataByIndex = (rowIndex) => {
|
||||
const getRowDataByIndex = (rowIndex, nodeId) => {
|
||||
if (!gridApi.value) {
|
||||
console.error('Grid API not available')
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
const node = gridApi.value.getDisplayedRowAtIndex(rowIndex)
|
||||
let node = null
|
||||
if (nodeId != null && gridApi.value.getRowNode) {
|
||||
node = gridApi.value.getRowNode(nodeId)
|
||||
}
|
||||
if (!node) {
|
||||
node = gridApi.value.getDisplayedRowAtIndex(rowIndex)
|
||||
}
|
||||
if (node && node.data) {
|
||||
return node.data
|
||||
}
|
||||
@@ -33,9 +41,10 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
const showDetails = (rowIndex, nodeId) => {
|
||||
console.log('Show details called with:', { rowIndex, nodeId })
|
||||
|
||||
const rowData = getRowDataByIndex(rowIndex)
|
||||
if (rowData) {
|
||||
selectedRowData.value = { ...rowData }
|
||||
const rowDataItem = getRowDataByIndex(rowIndex, nodeId)
|
||||
if (rowDataItem) {
|
||||
selectedRowData.value = { ...rowDataItem }
|
||||
selectedRowNodeId.value = nodeId
|
||||
showDetailsDialog.value = true
|
||||
console.log('Selected row data:', selectedRowData.value)
|
||||
} else {
|
||||
@@ -52,11 +61,15 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
}
|
||||
|
||||
try {
|
||||
gridApi.value.startEditingCell({
|
||||
rowIndex: rowIndex,
|
||||
colKey: 'fullName'
|
||||
})
|
||||
console.log('Started inline editing for row:', rowIndex)
|
||||
const columnDefs = typeof gridApi.value.getColumnDefs === 'function' ? gridApi.value.getColumnDefs() : []
|
||||
const firstEditableCol = Array.isArray(columnDefs) ? columnDefs.find(col => col && col.editable && col.field && col.field !== 'action') : null
|
||||
|
||||
if (firstEditableCol && typeof gridApi.value.startEditingCell === 'function') {
|
||||
gridApi.value.ensureIndexVisible?.(rowIndex)
|
||||
gridApi.value.setFocusedCell?.(rowIndex, firstEditableCol.field)
|
||||
gridApi.value.startEditingCell({ rowIndex, colKey: firstEditableCol.field })
|
||||
console.log('Started inline editing for row:', rowIndex)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error starting inline edit:', error)
|
||||
}
|
||||
@@ -65,9 +78,10 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
const deleteRow = (rowIndex, nodeId) => {
|
||||
console.log('Delete row called with:', { rowIndex, nodeId })
|
||||
|
||||
const rowData = getRowDataByIndex(rowIndex)
|
||||
if (rowData) {
|
||||
deleteRowData.value = { ...rowData }
|
||||
const rowDataItem = getRowDataByIndex(rowIndex, nodeId)
|
||||
if (rowDataItem) {
|
||||
deleteRowData.value = { ...rowDataItem }
|
||||
deleteRowNodeId.value = nodeId
|
||||
showDeleteDialog.value = true
|
||||
console.log('Delete row data:', deleteRowData.value)
|
||||
} else {
|
||||
@@ -78,26 +92,22 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
const confirmDelete = () => {
|
||||
if (deleteRowData.value && gridApi.value) {
|
||||
try {
|
||||
const indexToDelete = rowData.value.findIndex(item => {
|
||||
return (
|
||||
(item.id && item.id === deleteRowData.value.id) ||
|
||||
(item.email && item.email === deleteRowData.value.email) ||
|
||||
(item.fullName === deleteRowData.value.fullName &&
|
||||
item.salary === deleteRowData.value.salary)
|
||||
)
|
||||
})
|
||||
|
||||
// Prefer removing via grid transaction using the exact object
|
||||
gridApi.value.applyTransaction({ remove: [deleteRowData.value] })
|
||||
|
||||
// Also sync our local rowData list. Try by id first, else fallback to object equality
|
||||
let indexToDelete = -1
|
||||
if (deleteRowData.value.id != null) {
|
||||
indexToDelete = rowData.value.findIndex(item => item && item.id === deleteRowData.value.id)
|
||||
}
|
||||
if (indexToDelete === -1) {
|
||||
indexToDelete = rowData.value.findIndex(item => item === deleteRowData.value)
|
||||
}
|
||||
if (indexToDelete !== -1) {
|
||||
rowData.value.splice(indexToDelete, 1)
|
||||
|
||||
gridApi.value.applyTransaction({
|
||||
remove: [deleteRowData.value]
|
||||
})
|
||||
|
||||
console.log('Row deleted successfully')
|
||||
} else {
|
||||
console.error('Row not found for deletion')
|
||||
}
|
||||
|
||||
console.log('Row deleted successfully')
|
||||
} catch (error) {
|
||||
console.error('Error deleting row:', error)
|
||||
}
|
||||
@@ -105,6 +115,7 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
|
||||
showDeleteDialog.value = false
|
||||
deleteRowData.value = null
|
||||
deleteRowNodeId.value = null
|
||||
}
|
||||
|
||||
const cancelDelete = () => {
|
||||
@@ -116,25 +127,33 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
if (!editedData || !gridApi.value) return
|
||||
|
||||
try {
|
||||
const indexToUpdate = rowData.value.findIndex(item => {
|
||||
return (
|
||||
(item.id && item.id === editedData.id) ||
|
||||
(item.email && item.email === selectedRowData.value.email) ||
|
||||
(item.fullName === selectedRowData.value.fullName)
|
||||
)
|
||||
})
|
||||
|
||||
if (indexToUpdate !== -1) {
|
||||
rowData.value[indexToUpdate] = { ...editedData }
|
||||
|
||||
const node = gridApi.value.getRowNode(indexToUpdate)
|
||||
// Update the grid row via nodeId if available
|
||||
let updated = false
|
||||
if (selectedRowNodeId.value != null && gridApi.value.getRowNode) {
|
||||
const node = gridApi.value.getRowNode(selectedRowNodeId.value)
|
||||
if (node) {
|
||||
node.setData(editedData)
|
||||
updated = true
|
||||
}
|
||||
|
||||
console.log('User updated successfully:', editedData)
|
||||
}
|
||||
|
||||
// Sync local rowData list
|
||||
let indexToUpdate = -1
|
||||
if (editedData.id != null) {
|
||||
indexToUpdate = rowData.value.findIndex(item => item && item.id === editedData.id)
|
||||
}
|
||||
if (indexToUpdate === -1 && selectedRowData.value) {
|
||||
indexToUpdate = rowData.value.findIndex(item => item === selectedRowData.value)
|
||||
}
|
||||
if (indexToUpdate !== -1) {
|
||||
rowData.value[indexToUpdate] = { ...editedData }
|
||||
updated = true
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
console.log('Row updated successfully:', editedData)
|
||||
} else {
|
||||
console.error('User not found for update')
|
||||
console.error('Row not found for update')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating user:', error)
|
||||
@@ -142,6 +161,7 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
|
||||
showDetailsDialog.value = false
|
||||
selectedRowData.value = null
|
||||
selectedRowNodeId.value = null
|
||||
}
|
||||
|
||||
const exportToCSV = () => {
|
||||
@@ -163,7 +183,7 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
}
|
||||
|
||||
const exportToExcel = () => {
|
||||
if (gridApi.value) {
|
||||
if (gridApi.value && gridApi.value.exportDataAsExcel) {
|
||||
gridApi.value.exportDataAsExcel({
|
||||
fileName: `datatable-export-${new Date().toISOString().split('T')[0]}.xlsx`,
|
||||
sheetName: 'Data Export',
|
||||
@@ -176,6 +196,8 @@ export function useDataTableActions(gridApi, rowData) {
|
||||
allColumns: false,
|
||||
onlySelectedAllPages: false
|
||||
})
|
||||
} else {
|
||||
console.warn('Excel export not available - requires AG Grid Enterprise')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +1,52 @@
|
||||
import { ref, computed } from "vue";
|
||||
import { ref, computed, watch } from "vue";
|
||||
|
||||
export function useDataTableGrid(data, isMobile, isTablet) {
|
||||
export function useDataTableGrid(
|
||||
data,
|
||||
isMobile,
|
||||
isTablet,
|
||||
customColumns = null
|
||||
) {
|
||||
let gridApi = ref(null);
|
||||
const rowData = ref([]);
|
||||
|
||||
const statusCellRenderer = (params) => {
|
||||
const s = params.value;
|
||||
let label = "Applied";
|
||||
let colorClass = "info";
|
||||
|
||||
if (s === 1) {
|
||||
label = "Current";
|
||||
colorClass = "primary";
|
||||
}
|
||||
if (s === 2) {
|
||||
label = "Professional";
|
||||
colorClass = "success";
|
||||
}
|
||||
if (s === 3) {
|
||||
label = "Rejected";
|
||||
colorClass = "error";
|
||||
}
|
||||
if (s === 4) {
|
||||
label = "Resigned";
|
||||
colorClass = "warning";
|
||||
}
|
||||
const statusCellRenderer = (params) => {
|
||||
const s = params.value;
|
||||
let label = "Applied";
|
||||
let colorClass = "info";
|
||||
|
||||
const chipSize = isMobile.value ? "x-small" : "small";
|
||||
const fontSize = isMobile.value ? "10px" : "12px";
|
||||
if (s === 1) {
|
||||
label = "Current";
|
||||
colorClass = "primary";
|
||||
}
|
||||
if (s === 2) {
|
||||
label = "Professional";
|
||||
colorClass = "success";
|
||||
}
|
||||
if (s === 3) {
|
||||
label = "Rejected";
|
||||
colorClass = "error";
|
||||
}
|
||||
if (s === 4) {
|
||||
label = "Resigned";
|
||||
colorClass = "warning";
|
||||
}
|
||||
|
||||
return `<div class="v-chip v-chip--size-${chipSize} v-chip--variant-flat bg-${colorClass}"
|
||||
style="
|
||||
height:${isMobile.value ? "20px" : "24px"};
|
||||
padding:0 ${isMobile.value ? "6px" : "8px"};
|
||||
display:inline-flex;
|
||||
align-items:center;
|
||||
border-radius:12px;
|
||||
font-size:${fontSize};
|
||||
font-weight:500;
|
||||
color:white;
|
||||
border: inherit;
|
||||
">${label}</div>`;
|
||||
};
|
||||
const chipSize = isMobile.value ? "x-small" : "small";
|
||||
const fontSize = isMobile.value ? "10px" : "12px";
|
||||
|
||||
return `<div class="v-chip v-chip--size-${chipSize} v-chip--variant-flat bg-${colorClass}"
|
||||
style="
|
||||
height:${isMobile.value ? "20px" : "24px"};
|
||||
padding:0 ${isMobile.value ? "6px" : "8px"};
|
||||
display:inline-flex;
|
||||
align-items:center;
|
||||
border-radius:12px;
|
||||
font-size:${fontSize};
|
||||
font-weight:500;
|
||||
color:white;
|
||||
border: inherit;
|
||||
">${label}</div>`;
|
||||
};
|
||||
|
||||
const statusCellEditor = () => {
|
||||
const statusOptions = [
|
||||
@@ -239,7 +244,7 @@ const statusCellRenderer = (params) => {
|
||||
`;
|
||||
};
|
||||
|
||||
const columnDefs = ref([
|
||||
const createDefaultColumns = () => [
|
||||
{
|
||||
headerName: "NAME",
|
||||
field: "fullName",
|
||||
@@ -253,9 +258,6 @@ const statusCellRenderer = (params) => {
|
||||
cellEditorParams: {
|
||||
maxLength: 50,
|
||||
},
|
||||
onCellValueChanged: (params) => {
|
||||
console.log("Name changed:", params.newValue);
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: "EMAIL",
|
||||
@@ -270,9 +272,6 @@ const statusCellRenderer = (params) => {
|
||||
cellEditorParams: {
|
||||
maxLength: 100,
|
||||
},
|
||||
onCellValueChanged: (params) => {
|
||||
console.log("Email changed:", params.newValue);
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: "DATE",
|
||||
@@ -284,26 +283,17 @@ const statusCellRenderer = (params) => {
|
||||
hide: false,
|
||||
editable: true,
|
||||
cellEditor: "agDateCellEditor",
|
||||
cellEditorParams: {
|
||||
preventEdit: (params) => {
|
||||
return false;
|
||||
},
|
||||
},
|
||||
valueFormatter: (params) => {
|
||||
if (!params.value) return "";
|
||||
|
||||
const date = new Date(params.value);
|
||||
if (isNaN(date.getTime())) return "";
|
||||
|
||||
const day = date.getDate().toString().padStart(2, "0");
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||
const year = date.getFullYear();
|
||||
|
||||
return `${day}/${month}/${year}`;
|
||||
},
|
||||
valueParser: (params) => {
|
||||
if (!params.newValue) return null;
|
||||
|
||||
const dateStr = params.newValue;
|
||||
if (typeof dateStr === "string" && dateStr.includes("/")) {
|
||||
const parts = dateStr.split("/");
|
||||
@@ -311,14 +301,12 @@ const statusCellRenderer = (params) => {
|
||||
const day = parseInt(parts[0]);
|
||||
const month = parseInt(parts[1]) - 1;
|
||||
const year = parseInt(parts[2]);
|
||||
|
||||
const date = new Date(year, month, day);
|
||||
if (!isNaN(date.getTime())) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Date(dateStr);
|
||||
},
|
||||
filterParams: {
|
||||
@@ -327,14 +315,11 @@ const statusCellRenderer = (params) => {
|
||||
suppressAndOrCondition: true,
|
||||
comparator: (filterLocalDateAtMidnight, cellValue) => {
|
||||
if (!cellValue) return -1;
|
||||
|
||||
const cellDate = new Date(cellValue);
|
||||
cellDate.setHours(0, 0, 0, 0);
|
||||
|
||||
if (filterLocalDateAtMidnight.getTime() === cellDate.getTime()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return filterLocalDateAtMidnight < cellDate ? -1 : 1;
|
||||
},
|
||||
},
|
||||
@@ -408,7 +393,6 @@ const statusCellRenderer = (params) => {
|
||||
precision: 0,
|
||||
showStepperButtons: false,
|
||||
},
|
||||
|
||||
valueFormatter: (params) => {
|
||||
if (
|
||||
params.value === null ||
|
||||
@@ -420,7 +404,6 @@ const statusCellRenderer = (params) => {
|
||||
const numValue = Number(params.value);
|
||||
return isNaN(numValue) ? "" : Math.floor(numValue).toString();
|
||||
},
|
||||
|
||||
onCellValueChanged: (params) => {
|
||||
const newValue = params.newValue;
|
||||
|
||||
@@ -477,11 +460,60 @@ const statusCellRenderer = (params) => {
|
||||
hide: false,
|
||||
editable: false,
|
||||
cellRenderer: actionButtonsRenderer,
|
||||
suppressMenu: true,
|
||||
suppressSorting: true,
|
||||
suppressFilter: true,
|
||||
suppressHeaderMenuButton: true,
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
const resolveColumns = () => {
|
||||
if (Array.isArray(customColumns)) return customColumns
|
||||
if (customColumns && Array.isArray(customColumns.value)) return customColumns.value
|
||||
return []
|
||||
}
|
||||
|
||||
const processCustomColumns = (columns) => {
|
||||
if (!Array.isArray(columns) || columns.length === 0) {
|
||||
const base = createDefaultColumns();
|
||||
return ensureSingleSelectionColumn(base);
|
||||
}
|
||||
|
||||
const processedColumns = columns.map(col => ({
|
||||
...col,
|
||||
// Default to inline-editable unless explicitly disabled, skip action column
|
||||
editable: col.field === 'action' ? false : (col.editable !== undefined ? col.editable : true),
|
||||
suppressHeaderMenuButton: col.suppressHeaderMenuButton !== undefined ? col.suppressHeaderMenuButton : false,
|
||||
}));
|
||||
|
||||
const withSelection = ensureSingleSelectionColumn(processedColumns);
|
||||
|
||||
const hasActionColumn = processedColumns.some(col => col.field === 'action');
|
||||
|
||||
if (!hasActionColumn) {
|
||||
withSelection.push({
|
||||
headerName: "ACTION",
|
||||
field: "action",
|
||||
sortable: false,
|
||||
filter: false,
|
||||
flex: 1,
|
||||
minWidth: 100,
|
||||
hide: false,
|
||||
editable: false,
|
||||
cellRenderer: actionButtonsRenderer,
|
||||
suppressHeaderMenuButton: true,
|
||||
});
|
||||
}
|
||||
|
||||
return withSelection;
|
||||
};
|
||||
|
||||
const columnDefs = computed(() => {
|
||||
const cols = resolveColumns()
|
||||
if (cols && Array.isArray(cols) && cols.length > 0) {
|
||||
const processed = processCustomColumns(cols);
|
||||
return processed;
|
||||
}
|
||||
const defaultCols = createDefaultColumns();
|
||||
return ensureSingleSelectionColumn(defaultCols);
|
||||
});
|
||||
|
||||
const defaultColDef = computed(() => ({
|
||||
resizable: true,
|
||||
@@ -494,7 +526,7 @@ const statusCellRenderer = (params) => {
|
||||
maxWidth: 400,
|
||||
wrapText: false,
|
||||
autoHeight: false,
|
||||
suppressMenu: false,
|
||||
suppressHeaderMenuButton: false,
|
||||
}));
|
||||
|
||||
const gridOptions = computed(() => ({
|
||||
@@ -502,12 +534,16 @@ const statusCellRenderer = (params) => {
|
||||
headerHeight: isMobile.value ? 48 : 56,
|
||||
rowHeight: isMobile.value ? 44 : 52,
|
||||
animateRows: true,
|
||||
rowSelection: { type: "multiRow" },
|
||||
getRowId: params => {
|
||||
const value = params.data && (params.data.id ?? params.data.ID ?? params.data._id)
|
||||
return value != null ? String(value) : String(params.rowIndex)
|
||||
},
|
||||
rowSelection: 'multiple',
|
||||
rowMultiSelectWithClick: true,
|
||||
suppressRowClickSelection: false,
|
||||
pagination: true,
|
||||
paginationPageSize: isMobile.value ? 5 : 10,
|
||||
paginationPageSizeSelector: isMobile.value ? [5, 10, 20] : [5, 10, 20, 50],
|
||||
suppressRowClickSelection: false,
|
||||
rowMultiSelectWithClick: true,
|
||||
enableCellTextSelection: true,
|
||||
suppressHorizontalScroll: false,
|
||||
alwaysShowHorizontalScroll: false,
|
||||
@@ -527,55 +563,81 @@ const statusCellRenderer = (params) => {
|
||||
cacheQuickFilter: true,
|
||||
enableAdvancedFilter: false,
|
||||
includeHiddenColumnsInAdvancedFilter: false,
|
||||
suppressBrowserResizeObserver: false,
|
||||
maintainColumnOrder: true,
|
||||
suppressMenuHide: true,
|
||||
enableRangeSelection: true,
|
||||
enableFillHandle: false,
|
||||
enableRangeHandle: false,
|
||||
loading: false,
|
||||
suppressNoRowsOverlay: false,
|
||||
}));
|
||||
|
||||
const updateColumnVisibility = () => {
|
||||
if (!gridApi.value) return;
|
||||
|
||||
if (isMobile.value) {
|
||||
gridApi.value.setColumnVisible("email", false);
|
||||
gridApi.value.setColumnVisible("startDate", false);
|
||||
gridApi.value.setColumnVisible("age", false);
|
||||
} else if (isTablet.value) {
|
||||
gridApi.value.setColumnVisible("email", true);
|
||||
gridApi.value.setColumnVisible("startDate", false);
|
||||
gridApi.value.setColumnVisible("age", true);
|
||||
} else {
|
||||
gridApi.value.setColumnVisible("email", true);
|
||||
gridApi.value.setColumnVisible("startDate", true);
|
||||
gridApi.value.setColumnVisible("age", true);
|
||||
const columns = ['email', 'startDate', 'age'];
|
||||
|
||||
try {
|
||||
columns.forEach(colId => {
|
||||
const column = gridApi.value.getColumn ? gridApi.value.getColumn(colId) : null;
|
||||
if (!column) return;
|
||||
|
||||
let visible = true;
|
||||
if (isMobile.value) {
|
||||
visible = false;
|
||||
} else if (isTablet.value) {
|
||||
visible = colId !== 'startDate';
|
||||
}
|
||||
|
||||
if (gridApi.value.setColumnVisible) {
|
||||
gridApi.value.setColumnVisible(colId, visible);
|
||||
} else if (gridApi.value.columnApi && gridApi.value.columnApi.setColumnVisible) {
|
||||
gridApi.value.columnApi.setColumnVisible(colId, visible);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('Column visibility update not supported in this AG Grid version');
|
||||
}
|
||||
};
|
||||
|
||||
const updatePagination = () => {
|
||||
if (!gridApi.value) return;
|
||||
|
||||
const pageSize = isMobile.value ? 5 : 10;
|
||||
const pageSizeSelector = isMobile.value ? [5, 10, 20] : [5, 10, 20, 50];
|
||||
try {
|
||||
const gui = gridApi.value.getGui && gridApi.value.getGui();
|
||||
const containerHeight = gui ? gui.clientHeight : 0;
|
||||
|
||||
gridApi.value.paginationSetPageSize(pageSize);
|
||||
gridApi.value.setGridOption("paginationPageSizeSelector", pageSizeSelector);
|
||||
const headerH = Number(gridOptions.value.headerHeight || (isMobile.value ? 48 : 56));
|
||||
// Estimate footer height based on overrides (mobile/desktop)
|
||||
const footerH = isMobile.value ? 48 : 56;
|
||||
const rowH = Number(gridOptions.value.rowHeight || (isMobile.value ? 44 : 52));
|
||||
const padding = 8;
|
||||
|
||||
let available = containerHeight - headerH - footerH - padding;
|
||||
if (!Number.isFinite(available) || available <= 0) {
|
||||
available = (isMobile.value ? 360 : 520) - headerH - footerH - padding;
|
||||
}
|
||||
|
||||
let rowsPerPage = Math.floor(available / rowH);
|
||||
rowsPerPage = Math.max(3, Math.min(rowsPerPage, 100));
|
||||
|
||||
if (typeof gridApi.value.paginationSetPageSize === 'function') {
|
||||
gridApi.value.paginationSetPageSize(rowsPerPage);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Error updating pagination:', error);
|
||||
}
|
||||
};
|
||||
|
||||
function onGridReady(params) {
|
||||
console.log('Grid ready called with params:', params)
|
||||
gridApi.value = params.api;
|
||||
rowData.value = data.map((item) => ({
|
||||
...item,
|
||||
salary:
|
||||
typeof item.salary === "string" ? parseInt(item.salary) : item.salary,
|
||||
age: typeof item.age === "string" ? parseInt(item.age) : item.age,
|
||||
}));
|
||||
console.log('Grid API set:', gridApi.value)
|
||||
|
||||
updateColumnVisibility();
|
||||
updatePagination();
|
||||
|
||||
setTimeout(() => {
|
||||
gridApi.value.sizeColumnsToFit();
|
||||
if (gridApi.value && gridApi.value.sizeColumnsToFit) {
|
||||
gridApi.value.sizeColumnsToFit();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
@@ -600,6 +662,17 @@ const statusCellRenderer = (params) => {
|
||||
}
|
||||
}
|
||||
|
||||
watch([isMobile, isTablet], () => {
|
||||
updateColumnVisibility();
|
||||
updatePagination();
|
||||
});
|
||||
|
||||
watch(data, (newData) => {
|
||||
console.log('Data watch triggered with:', newData)
|
||||
rowData.value = newData || [];
|
||||
console.log('rowData updated to:', rowData.value)
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
return {
|
||||
gridApi,
|
||||
columnDefs,
|
||||
@@ -611,4 +684,36 @@ const statusCellRenderer = (params) => {
|
||||
updateColumnVisibility,
|
||||
updatePagination,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
function ensureSingleSelectionColumn(columns) {
|
||||
if (!Array.isArray(columns)) return columns;
|
||||
|
||||
const isSelectionCol = (c) => !!(c && (c.checkboxSelection || c.headerCheckboxSelection || c.field === '__selection__' || c.field === 'selection'));
|
||||
|
||||
const firstIndex = columns.findIndex(isSelectionCol);
|
||||
if (firstIndex === -1) return columns;
|
||||
|
||||
const unique = [];
|
||||
columns.forEach((c, idx) => {
|
||||
if (isSelectionCol(c)) {
|
||||
if (unique.some(isSelectionCol)) return; // skip duplicates
|
||||
unique.push({ ...c, pinned: 'left' });
|
||||
} else {
|
||||
unique.push(c);
|
||||
}
|
||||
});
|
||||
|
||||
// Move the selection column to the first position
|
||||
const selIdx = unique.findIndex(isSelectionCol);
|
||||
if (selIdx > 0) {
|
||||
const [sel] = unique.splice(selIdx, 1);
|
||||
unique.unshift(sel);
|
||||
}
|
||||
|
||||
return unique;
|
||||
}
|
||||
|
||||
// removed selection column injection
|
||||
Reference in New Issue
Block a user