Perspective table assistance

I’m trying accomplish what seems to a “very simple” task in perspective on a table and am having some trouble with a solution. When a user clicks on a cell on the table to edit it, after they press Tab key on the keyboard, I want to set the value to the cell where the edit occurred and jump to the next column. I have come across some JS code on the forum using the markdown component but still have not found a solution that I’m looking for. Any suggestions, advice or pointers are greatly appreciated.

This is actually going to be very complicated, because you're trying to move from an ephemeral input to another input which does not yet exist.

Precondition:
Every column of the Table must be configured to be editable.

To manage this, you'll need to configure a key event for TAB, which broadcasts a message at the Session scope.

	system.perspective.sendMessage("TAB_PRESSED", scope="session", sessionId=page.session.props.id, pageId=page.id)

Next, you'll have to configure a listener for your Table to listen for this message and update the location of the cell open for editing.

def onMessageReceived(self, payload):
	editingCell = self.props.editingCell
	if editingCell.row != "" and editingCell.column != "":
		bump_row = False
		row = editingCell.row
		column = editingCell.column
		# begin updating column
		if column == self.props.columns[-1].field:
			# If we're already the last column, loop back to the front and next row
			self.props.editingCell.column = self.props.columns[0].field
			bump_row = True
		else:
			current_column_index = -1
			for i in range(len(self.props.columns) - 1):
				if self.props.columns[i].field == column:
					current_column_index = i
			if current_column_index == -1:
				raise ValueError("Unable to locate current columnn index!")
			else:
				self.props.editingCell.column = self.props.columns[current_column_index + 1].field
		# begin updating row
		if bump_row and row < len(self.props.data):
			self.props.editingCell.row = row + 1

I've tested this and it works well, but we're being greedy with focus here. The native browser behavior is to apply focus to the next component based on tab index, so if you have a busy View you'll notice that when you press TAB something else gains focus, but then we steal it back for the Table. Additionally, if your user is editing a cell, clicks outside the table, then clicks TAB the behavior gets a little weird.

2 Likes

A team member raised a scenario where you might want to actually commit a value (Enter) and then TAB to the next cell. To manage this, you'll need a custom property which acts as the registry of the latest valid value combo for the editingCell object. I'd recommend a change script attached to the object:

if currentValue:
    if currentValue.value.row != "" and currentValue.value.column != "":
        # only write to the custom object if both values are valid
        self.custom.editingCell = currentValue.value

Then you would amend the script I provided earlier to use this custom object instead of Table.props.editingCell.

@cmallonee Thank you for the quick response and additional insight. It's greatly appreciated. I have not done a lot with messaging, I usually try to keep the processing and logic as close to the component as possible. Sometimes that works, there is component capability and sometimes you just have to improvise. Thank you again.

1 Like