[IGN-7140] Perspective Table - add `props.selection.selectedRows`

Currently, it's difficult to process actions on a range of selected rows, since we don't have access in the selection data to which row indexes are selected, we can only see the data in the rows, and the last selected row index.
It would be useful to add a props.selection.selectedRows as a list which contains the row indexes selected.

For example, I want users to be able to select a bunch of rows and use a button to move the data in those rows to somewhere else and then remove those rows from the table. Removing the rows is hard!

Current thinking is that I will add the props.selection.selectedRow value into a custom.selectedRows list on row click, and keep the list the length of the props.selection.data list length using FIFO. Certainly not very nice

E.g.

# on rowClick
def runAction(self, event):
	selectedRow = event.rowIndex
	selectionLength = len(self.props.selection.data)
	
	selectedRows = self.custom.selectedRows
	selectedRows.append(selectedRow)
	selectedRows = selectedRows[-1*selectionLength:]
	
	self.custom.selectedRows = selectedRows

I would do something like this:

Expression binding bound to this.props.selection.data

data = [{k: v.get('value') if hasattr(v, 'has_key') else v for k, v in rowData.iteritems()} for rowData in self.props.data]
return [data.index(dict(v)) for v in value]

But even then... i don't fully like it. If you have duplicate rows, it may return the incorrect row? I guess if each row had a unique identifying key, you could check against that to verify you have the correct row.

Your current run action doesn't work correctly if you shift click to select multiple in one go.

Bummer, so it doesn't... my next option would have been your way, although yours looks more sophisticated than what I was going to do :sweat_smile: so i might just borrow yours, thanks!

1 Like

While I'm open to the idea of this feature, there's a potential problem we could run into...

This feature requires some new value be injected into each row selected so that we have a structure approximating this within props.selection.data[x]:
Screenshot 2023-02-03 at 9.44.45 AM

You can probably see why this might be a problem; what if the data of the table already contains a column with a key of index? We've just overwritten the user's data with our own injected value. As we try to settle on a key that clearly conveys what our injected value would be, we would have to tread a fine line between making it simple enough to be useful, but unique enough to have 0% chance of clobbering a user's existing data.

I'm less open to the idea of props.selection.selectedRows because that's a near duplication of selectedRow. That's not to say we couldn't do it, but... ew. Maybe we deprecate selectedRow for 8.3 and replace it with selectedRows? That might work.

Yep, agreed it's ugly having both. Only reason to do that was for backwards compatibility, but certainly better to remove selectedRow in favour of selectedRows.

Inserting the 'index' into the selection.data is definitely not something IA should be doing for your exact reason, unless the name of the key is configurable, which would be useful!

The issue I have is manipulating rows when clicking on views used in the table cells, as the only link you have back to the table row from within the cell view is via the rowData passed into it.

1 Like

As per usual, I'm a year-late to the topic...
@nminchin, Correct me if I'm mistaken, but I believe the Tree component has the feature (multi-selection indexing) that you're requesting.

image

@cmallonee, I'm struggling to understand why user data would have to be transformed to handle this request? I am stuck with a feeling that adding a key (of any name) with a value that ALWAYS matches the data[#] index is a bit redundant. Obviously, the details matter here, but wondering if you can shed some light?
I'm hoping that the more difficult problem is how to handle backwards compatibility while keeping property list 'clean'.

While it's true the Table has props.selectionData, the objects in that list contain only the data of the row, with no insight into the index of the row in the dataset/list.

Consider the following data value, where an object seems to be repeated:

[
    {"name": "A", "value": 1},
    {"name": "B", "value": 2},
    {"name": "C", "value": 3},
    {"name": "A", "value": 1}
]

If a user selects the last row of the data, how are you to know if props.selectionData represents the first or last row of data? Due to the complete dataset containing no guaranteed unique value, there is no way to perform something like an update query based on the provided data. FOr Perspective to expose which row is truly selected, we would need to inject some sort of index property, which would reflect the 0-based index of the row each entry in props.selectionData represents.

Now, here's the problem: what if users have prepared their data with an index key which actually means something to them?

# select * from MyTable where index<30;
[
    {"index": 1, "name": "A", "value": 1},
    {"index": 15, "name": "B", "value": 2},
    {"index": 20, "name": "C", "value": 3},
    {"index": 21, "name": "A", "value": 1}
]

If a user clicks the last row again, we can't run the risk of replacing 21 with 3.

I see!
I was assuming (shame on me) that the props.selectionData object (of the Table component) was a derivative of (populated by) the props.selection object. I see now that the manual modification of one has no effect on the other...
Perhaps one way to accommodate the request (for 8.3) would be to:
a) Move any configuration props out of the props.selection object to a new props.config object, and make props.selection an array.
b) Move the selection data array values to a child object of the respective array, whose siblings contain the new index prop(s). Something resembling:
image
:thinking:

While that might function, it's also a surprisingly big ask because we're unlikely to just remove the existing props in favor of this pattern, which would leave us with nearly identical data structures which both more-or-less represent the same data. We're actually more likely to modify the structure of the existing selection array than we are to introduce a sibling which does essentially the same thing.

While 8.3 affords us the option to introduce "breaking" changes to the product, we still intend to only do so in spots where it absolutely must be done to advance the product - and this does not seem to be one of those spots.