Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(table): expose sort function #959

Merged
merged 1 commit into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/docs/components/Table.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ sidebarDepth: 2
| customDetailRow | Enable custom style on details (if detailed) | boolean | - | <code style='white-space: nowrap; padding: 0;'>false</code> |
| data | Table data | T[] | - | Default function (see source code) |
| debounceSearch | Filtering debounce time (in milliseconds) | number | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>table: {<br>&nbsp;&nbsp;debounceSearch: undefined<br>}</code> |
| defaultSort | Sets the default sort column and order — e.g. ['first_name', 'desc'] | string \| string[] | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>table: {<br>&nbsp;&nbsp;defaultSort: undefined<br>}</code> |
| defaultSort | Sets the default sort column and order — e.g. 'first_name' or ['first_name', 'desc'] | string \| [string, "asc" \| "desc"] | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>table: {<br>&nbsp;&nbsp;defaultSort: undefined<br>}</code> |
| defaultSortDirection | Sets the default sort column direction on the first click | string | `asc`, `desc` | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>table: {<br>&nbsp;&nbsp;defaultSortDirection: "asc"<br>}</code> |
| detailIcon | Icon name of detail action (if detailed) | string | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>table: {<br>&nbsp;&nbsp;detailIcon: "chevron-right"<br>}</code> |
| detailTransition | | string | - | <div><small>From <b>config</b>:</small></div><code style='white-space: nowrap; padding: 0;'>table: {<br>&nbsp;&nbsp;detailTransition: "slide"<br>}</code> |
Expand Down
77 changes: 39 additions & 38 deletions packages/oruga/src/components/table/Table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ import type {
} from "./types";
import type { ComponentClass, ClassBind, OrugaOptions } from "@/types";

enum SortDirection {
ASC = "asc",
DESC = "desc",
}

/**
* Tabulated data are sometimes needed, it's even better when it's responsive
* @displayName Table
Expand Down Expand Up @@ -193,17 +198,18 @@ const props = defineProps({
type: Boolean,
default: () => getOption("table.backendSorting", false),
},
/** Sets the default sort column and order — e.g. ['first_name', 'desc'] */
/** Sets the default sort column and order — e.g. 'first_name' or ['first_name', 'desc'] */
defaultSort: {
type: [String, Array] as PropType<string | string[]>,
type: [String, Array] as PropType<string | [string, "asc" | "desc"]>,
default: () => getOption("table.defaultSort"),
},
/**
* Sets the default sort column direction on the first click
* @values asc, desc
*/
defaultSortDirection: {
type: String,
type: String as PropType<"asc" | "desc">,
validator: (value: string) => ["asc", "desc"].indexOf(value) >= 0,
default: () => getOption("table.defaultSortDirection", "asc"),
},
/** Sets the header sorting icon */
Expand Down Expand Up @@ -1070,8 +1076,6 @@ function filterRows(rows: TableRow<T>[]): TableRow<T>[] {
const currentSortColumn = ref<TableColumnItem<T>>();
const isAsc = ref(true);

onMounted(() => nextTick(() => checkSort()));

/** check if has any sortable column */
const hasSortableColumns = computed(() =>
tableColumns.value.some((column) => column.sortable),
Expand All @@ -1082,44 +1086,23 @@ function isColumnSorted(column: TableColumnItem<T>): boolean {
return currentSortColumn.value?.identifier === column.identifier;
}

/** call initSort only first time (For example async data) */
function checkSort(): void {
if (tableColumns.value.length && !currentSortColumn.value) {
// is first time sort
initSort();
} else if (tableColumns.value.length) {
if (
currentSortColumn.value &&
Object.keys(currentSortColumn.value).length > 0
) {
const column = tableColumns.value.find(
(column) => currentSortColumn.value.field === column.field,
);
if (column) currentSortColumn.value = column;
}
}
}
// call initSort only first time (for example async data)
// initSort must be called after TableColumns got initialised first time
onMounted(() => nextTick(() => initSort()));

/** initial sorted column based on the default-sort prop */
function initSort(): void {
if (!tableColumns.value.length || currentSortColumn.value) return;
if (!props.defaultSort) return;
let sortField = "";
let sortDirection = props.defaultSortDirection;
if (Array.isArray(props.defaultSort)) {
sortField = props.defaultSort[0];
if (props.defaultSort[1]) {
sortDirection = props.defaultSort[1];
}
if (props.defaultSort[1]) sortDirection = props.defaultSort[1];
} else {
sortField = props.defaultSort;
}
const sortColumn = tableColumns.value.find(
(column) => column.field === sortField,
);
if (sortColumn) {
isAsc.value = sortDirection.toLowerCase() !== "desc";
sort(sortColumn, true);
}
sortByField(sortField, sortDirection as SortDirection);
}

/**
Expand All @@ -1134,20 +1117,38 @@ function sort(
): void {
if (!column || !column.sortable) return;

if (!updateDirection)
if (updateDirection)
isAsc.value = isColumnSorted(column)
? !isAsc.value
: props.defaultSortDirection.toLowerCase() !== "desc";
: props.defaultSortDirection.toLowerCase() === SortDirection.ASC;

// if not first time sort
if (currentSortColumn.value)
emits("sort", column, isAsc.value ? "asc" : "desc", event);
emits(
"sort",
column,
isAsc.value ? SortDirection.ASC : SortDirection.DESC,
event,
);

currentSortColumn.value = column;
// recompute rows with updated currentSortColumn
processTableData();
}

function sortByField(
field: string,
direction: SortDirection = SortDirection.ASC,
): void {
const sortColumn = tableColumns.value.find(
(column) => column.field === field,
);
if (sortColumn) {
isAsc.value = direction.toLowerCase() === SortDirection.ASC;
sort(sortColumn);
}
}

function sortByColumn(rows: TableRow<T>[]): TableRow<T>[] {
const column = currentSortColumn.value;
if (!column) return rows;
Expand Down Expand Up @@ -1559,7 +1560,7 @@ function tdClasses(row: TableRow<T>, column: TableColumnItem<T>): ClassBind[] {
// --- Expose Public Functionalities ---

/** expose functionalities for programmatic usage */
defineExpose({ rows: tableData });
defineExpose({ rows: tableData, sort: sortByField });
</script>

<template>
Expand Down Expand Up @@ -1601,7 +1602,7 @@ defineExpose({ rows: tableData });
:sort-icon-size="sortIconSize"
:is-asc="isAsc"
:mobile-sort-classes="mobileSortClasses"
@sort="(column, event) => sort(column, null, event)" />
@sort="(column, event) => sort(column, true, event)" />

<template
v-if="
Expand Down Expand Up @@ -1701,7 +1702,7 @@ defineExpose({ rows: tableData });
:class="thClasses(column)"
:style="isMobileActive ? {} : column.style"
:draggable="canDragColumn"
@click.stop="sort(column, null, $event)"
@click.stop="sort(column, true, $event)"
@dragstart="
handleColumnDragStart(column, index, $event)
"
Expand Down
4 changes: 1 addition & 3 deletions packages/oruga/src/components/table/examples/async-data.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ const data = ref([]);
const total = ref(0);
const loading = ref(false);
const sortField = ref("vote_count");
const sortOrder = ref("desc");
const defaultSortOrder = ref("desc");
const sortOrder = ref<"asc" | "desc">("desc");
const page = ref(1);
const perPage = ref(20);

Expand Down Expand Up @@ -93,7 +92,6 @@ onMounted(() => {
:total="total"
:per-page="perPage"
backend-sorting
:default-sort-direction="defaultSortOrder"
:default-sort="[sortField, sortOrder]"
aria-next-label="Next page"
aria-previous-label="Previous page"
Expand Down
14 changes: 9 additions & 5 deletions packages/oruga/src/components/table/examples/customise.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,33 +82,37 @@ const hasMobileCards = ref(true);
field="id"
label="ID"
width="40"
numeric>
numeric
sortable>
{{ row.id }}
</o-table-column>

<o-table-column
v-slot="{ row }"
field="first_name"
label="First Name">
label="First Name"
sortable>
{{ row.first_name }}
</o-table-column>

<o-table-column
v-slot="{ row }"
field="last_name"
label="Last Name">
label="Last Name"
sortable>
{{ row.last_name }}
</o-table-column>

<o-table-column
v-slot="{ row }"
field="date"
label="Date"
position="centered">
position="centered"
sortable>
{{ new Date(row.date).toLocaleDateString() }}
</o-table-column>

<o-table-column v-slot="{ row }" label="Gender">
<o-table-column v-slot="{ row }" label="Gender" sortable>
<o-icon
pack="fas"
:icon="row.gender === 'Male' ? 'mars' : 'venus'" />
Expand Down
1 change: 0 additions & 1 deletion packages/oruga/src/components/table/examples/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,3 @@ import DraggableCode from "./draggable.vue?raw";
<h3 id="draggable">Draggable rows/columns</h3>
<ExampleViewer :component="Draggable" :code="DraggableCode" />
</template>
./draggable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ const isPaginationSimple = ref(false);
const paginationPosition = ref("bottom");
const sortIcon = ref("arrow-up");
const sortIconSize = ref("small");
const defaultSortDirection = ref("asc");
const defaultSortDirection = ref<"asc" | "desc">("asc");
const currentPage = ref(1);
const perPage = ref(3);
</script>
Expand Down
6 changes: 3 additions & 3 deletions packages/oruga/src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1268,10 +1268,10 @@ but will set body to position fixed, might break some layouts. */
hoverable: boolean;
/** Select placeholder text when nothing is selected (if mobileCards) */
mobileSortPlaceholder: string;
/** Sets the default sort column and order — e.g. ['first_name', 'desc'] */
defaultSort: string | string[];
/** Sets the default sort column and order — e.g. 'first_name' or ['first_name', 'desc'] */
defaultSort: string | [string, "asc" | "desc"];
/** Sets the default sort column direction on the first click */
defaultSortDirection: string;
defaultSortDirection: "asc" | "desc";
/** Sets the header sorting icon */
sortIcon: string;
/** Sets the size of the sorting icon */
Expand Down
Loading