QTable question: Sort by selected/deselected rows
-
In a q-table, if selection=“multiple” is specified, Quasar automatically creates a first column that contains a q-checkbox per row to select and deselect rows. It also creates a queckbox in the upper left corner of the table that allows to select/de-select all rows (selection column/header row).
Is there a way to customize this “selection column”, to allow sorting of rows by the selected/deselected property managed in this column, in the same way it happens for other columns that have “sortable: true”? For those regular “sortable” columns, Quasar creates a small arrow button in the header row, right to the column name, to control the sorting.
There is an example in the q-table docs under “Expanded row and custom selector” to insert a custom selector (q-toggle in that example) into the first column (for the regular rows, not the header) through the use of a v-slot, but it is beyond my imagination whether and how one can also get control over that “select/de-select all” checkbox that Quasar displays in the upper left corner of the q-table.
-
Gentle reminder: I would appreciate some hint whether what I described above is possible through customization or would require a change in the Quasar q-table source code?
-
Did you mean to turn on/off the column sorting on each column dynamically?
-
Yes, what I mean is that, if selection=“multiple” is specified for the q-table, the user should be able to control the column sorting for that first, Quasar generated selected/deselected column (that shows Quasar generated q-checkboxes to select/deselect rows), in the same way that the user can control sorting for any other columns that have the “sortable” prop, through the little down/up arrows that show up in the table header for each “sortable” column.
The more I think about it myself, to get what I want would probably require a new prop selection=“sortable” (which would mean “multiple” and “sortable”), and a change in the q-table code that would show these up/down arrows also for the first column in the upper left corner (where the checkbox sits that allows to select/deselect all rows)…unless you know another way to achieve it, maybe through some magic custom code in the q-table header slot.
The reason behind this requirement: In a table that has many hundred rows on multiple pages, and a few rows to be selected on various pages, I would like to give the user, once he is done with his selections, the ability to view all selected rows together on the first table page(s), rather than having them spread across all pages.
When I say “table header”, I mean the table top row that has the column names etc., not sure about the slot naming.
-
Here is a screenshot that illustrates it - what I would like is basically an up/down arrow on the first column in that table which controls the selection, like for the third column named “Typ” (which is “sortable”):
-
@Mickey58 so you want the selected rows to show on top by adding a sort function beside the check all header right? You can issue as a feature request in github.
-
@metalsadman - yes, that’s it, so I’ll open a feature request.
-
@metalsadman effectively it could be handled by some kind of computed/virtual table column.
-
@qyloxe - do you mean it could be handled in that way not changing Quasar code? If yes, could you elaborate a bit how this could be done? My guess is that somehow you would customize the header slot for that first “checkbox” column, which is Quasar generated, but I would need some sample code to start with.
-
@Mickey58
in:
https://quasar.dev/vue-components/table#Defining-the-columnsthis is actual column definition:
{ // unique id (used by row-key, pagination.sortBy, ...) name: 'desc', // label for header label: 'Dessert (100g serving)', // row Object property to determine value for this column field: 'name', // OR field: row => row.some.nested.prop // (optional) if we use visible-columns, this col will always be visible required: true, // (optional) alignment align: 'left', // (optional) tell QTable you want this column sortable sortable: true, // (optional) compare function if you have // some custom data or want a specific way to compare two rows sort: (a, b, rowA, rowB) => parseInt(a, 10) - parseInt(b, 10), // function return value: // * is less than 0 then sort a to an index lower than b, i.e. a comes first // * is 0 then leave a and b unchanged with respect to each other, but sorted with respect to all different elements // * is greater than 0 then sort b to an index lower than a, i.e. b comes first // (optional) you can format the data with a function format: (val, row) => `${val}%`, style: 'width: 500px', classes: 'my-special-class' },
If you could define “virtual” columns, then you could sort/filter/select them also. In example:
{ // unique id (used by row-key, pagination.sortBy, ...) name: 'desc', // label for header label: 'Dessert (100g serving)', // (optional) alignment align: 'left', // (optional) tell QTable you want this column sortable sortable: true, value: (col, row) => this.selected.includes(row.id) },
the new column attribute “value” could be a “virtual”/“computed” column with parameters:
col - this col definition
row - actual row - based on other row values “value” function returns proper computed valueIt would solve your problem and many others.
-
@qyloxe: Thanks, this looks promising, but I’m still unsure how I would insert this “virtual column” into the first column, especially in the upper left cell of the header of the q-table.
I see various slots in the q-table API for it, q-header, q-header-cell, q-header-cell[-name], q-th - not sure how to use them… Do you have a sample that manipulates the q-table header slots?
Maybe I still misunderstand it, and you mean I should insert a new, second “virtual” column (after the first column that has the Quasar generated checkboxes for row selection) just for sorting of the first column, with that little up/down arrow in the header?
-
@metalsadman and @qyloxe:
I forked a q-table codepen from @metalsadman that happens to customize the q-table header: [https://codepen.io/mickey58/pen/XWWVEEN]
This is what I changed:
- I added a “selection=‘multiple’” to the q-table, which auto-generates checkboxes in the first column.
- I added two so far empty <q-th> </q-th> elements to get proper alignment of the table columns.
I’m unsure how I could get that additional checkbox for selecting/unselecting all rows in the upper left corner cell (which is normally generated by Quasar in case of selection=“multiple”) and how to get to my end goal of getting sorting on it.
Maybe you can have a look at my codepen and have a suggestion?
-
I was able to add the checkbox for selecting/unselecting all rows in the upper left corner cell (which is normally generated by Quasar in case of selection=“multiple”) in the codepen at [https://codepen.io/mickey58/pen/XWWVEEN].
And I looked up the Quasar q-table source code to see how it handles the sorting of columns. The little “up/down” arrow icons that trigger the sorting are generated through very specific CSS, not through regular q-buttons. So it would require complicated CSS on the html table element for the first column/second header row, to get those arrows into the custom header in the codepen. That goes, at the moment, a bit too far in terms of customizing q-table.
What remains to be looked at as an alternative is @qyloxe’ suggestion to implement sorting on the checkbox column (which has v-model=“props.selected”) through an (additional?) virtual column on props.selected. If triggering that sorting directly through an icon in the column header is difficult, it could still be triggered through a button outside of the q-table.
-
Like i said, you can issue a feature request for this, since those controls are internal, maybe just a scope slot for the multi selection th column so that you can customize it, relative props should also be exposed along with the functions that make the deselection/selection of all visible rows. And imo it look like a valid feature that can prove to be useful for others too. maybe @qyloxe can provide you a pen with his idea how to do it. Was trying it earlier, but you’ll have to reinvent how the selection/deselection function works, the sorting is not the problem.
-
@metalsadman @Mickey58
Well, I have a mixed feelings about incorporating virtual columns into q-table. This is obviously the preferred way for presentation of computed (on the client side) values - in this example it is the “is selected” column but it could be anything - the sum of two other columns, the abstract of the long text, the amount with added local tax etc.IMHO the real problem is a concept of “data model”. Of course we could extend the q-table capabilities, BUT very similar capabilities should be possible for other components - list, tree etc. I consider it a bad design if every component would have his own “rules” and separate “data model” to deal with.
I think, that at this moment Quasar is in need of a separate non-visual component for data modelling. There should be column definitions (also virtual/computed), pagination, sorting, filtering, querying, events for data loading, server synchronization etc. This non-visual component (or maybe class?) should be attached by composition to visual components like q-table, q-list, q-tree etc.
So, I am sure, the computed/virtual columns are the way to go, but I’m not so sure, it should be implemented exactly into the q-table.
-
@metalsadman and @qyloxe - thanks for your thoughts. I agree that this stretches the customization of q-table quite far, and I also agree with @qyloxe that putting it into Quasar has also its downsides. The more such extras you put in, the more complex and heavyweight the components and their interfaces get - keeping a clean outside and inside design is important.
Nevertheless, I now managed to put this extra sorting capability on selected/deselected columns in through customization - it is in this codepen derived from another QTable sample from @metalsadman : https://codepen.io/mickey58/pen/XWWVEEN
Could you please have a quick look at the script section? Unfortunately I did not succeed in doing the computation of whether a row is selected into a computed: function. It is in a method currently, because it needs the row as a parameter. And I have “stolen” the sort function for Booleans from some other forum post.
I’d appreciate if you have a quick look and comment whether it could be done better. Thanks.
-
@qyloxe i agree, thats why the composition api is coming to vue 3 for such cases. Like i was saying, this could be exposed by a scope slot as of now imo. @Mickey58 sry cant test this as of now (im at mobile atm, will take a look asap), like i said above the sorting is not the problem, but the deselection/selection, can be done but its reinvention, when its already in there internally just not exposed at current api.