# Perspective table assistance

**URL:** <https://forum.inductiveautomation.com/t/perspective-table-assistance/86640>\
**Category:** Ignition\
**Tags:** scripting, ignition81, perspective\
**Created:** [February 29, 2024, 11:05pm UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640 "2024-02-29T23:05:21Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![ademovicemir](https://avatars.discourse-cdn.com/v4/letter/a/bbce88/32.png) [@ademovicemir](https://forum.inductiveautomation.com/u/ademovicemir)\
**Post date:** [February 29, 2024, 11:05pm UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640/1 "2024-02-29T23:05:22Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![cmallonee](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmallonee/32/6416_2.png) [@cmallonee](https://forum.inductiveautomation.com/u/cmallonee)\
**Post date:** [March 1, 2024, 12:21am UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640/2 "2024-03-01T00:21:33Z")

</div>

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.

```auto
	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.

 ![Screenshot 2024-02-29 at 4.21.08 PM](https://us1.discourse-cdn.com/inductiveautomation/original/3X/5/b/5b64e58ad281dac69f94299b4067a1787a63d7f4.png)

```auto
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.

---

<div class="post-metadata">

**Author:** ![cmallonee](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmallonee/32/6416_2.png) [@cmallonee](https://forum.inductiveautomation.com/u/cmallonee)\
**Post date:** [March 1, 2024, 4:54pm UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640/3 "2024-03-01T16:54:56Z")

</div>

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:

```python
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`.

---

<div class="post-metadata">

**Author:** ![ademovicemir](https://avatars.discourse-cdn.com/v4/letter/a/bbce88/32.png) [@ademovicemir](https://forum.inductiveautomation.com/u/ademovicemir)\
**Post date:** [March 1, 2024, 5:19pm UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640/4 "2024-03-01T17:19:04Z")

</div>

@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.

---

<div class="post-metadata">

**Author:** ![Andrew\_Buldyzhov](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/andrew_buldyzhov/32/74246_2.png) [@Andrew\_Buldyzhov](https://forum.inductiveautomation.com/u/Andrew_Buldyzhov)\
**Post date:** [March 26, 2025, 1:43pm UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640/5 "2025-03-26T13:43:21Z")

</div>

Please advise how "a key event for TAB" should be configured. I've tried to create onKeyPress event in the Table component with the following script (and tried checking the "Prevent Default" checkbox on and off) but this script is not executed and the Tab key works as usual (moving between components).  
I also tried configuring onKeyPress event for the 'root' component.

```python
    if event.key == 'Tab':
        system.perspective.sendMessage("TAB_PRESSED", scope="session", sessionId=page.session.props.id, pageId=page.id)
    	system.perspective.print("Tab pressed -- message sent")
        event.preventDefault()

```

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 26, 2025, 1:52pm UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640/6 "2025-03-26T13:52:07Z")

</div>

I think @cmallonee might have meant a session keystroke event. Otherwise I'm not sure why a session wide message would be required.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/c/4/c442889c8b7a90f8953e49793b55e78c10b3b6b0.png)

---

<div class="post-metadata">

**Author:** ![Andrew\_Buldyzhov](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/andrew_buldyzhov/32/74246_2.png) [@Andrew\_Buldyzhov](https://forum.inductiveautomation.com/u/Andrew_Buldyzhov)\
**Post date:** [March 26, 2025, 4:18pm UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640/7 "2025-03-26T16:18:27Z")

</div>

Yes, the event works like this. Thank you!

---

<div class="post-metadata">

**Author:** ![Andrew\_Buldyzhov](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/andrew_buldyzhov/32/74246_2.png) [@Andrew\_Buldyzhov](https://forum.inductiveautomation.com/u/Andrew_Buldyzhov)\
**Post date:** [March 26, 2025, 4:33pm UTC](https://forum.inductiveautomation.com/t/perspective-table-assistance/86640/8 "2025-03-26T16:33:04Z")

</div>

@cmallonee , I had to refine your solution a bit. Posting it here in case somebody else may need it too.

Table \> editingCell \> Edit Change Script:

```python
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	if currentValue:
		if currentValue.value["row"].value != "" and currentValue.value["column"].value != "":
			# only write to the custom object if both values are valid
			self.custom.editingCell = currentValue.value

```

I have decided not to override Tab and Shift-Tab, because those keys have useful functionality in the browser (navigation between the components). I have also removed bump\_row (better for my case) so whoever needs it, may analyze my changes and add them in the initial solution:

Perspective \> Session Events \> Keystroke:  
[Conrol] ArrowLeft

```python
def onKeyEvent(page, event):
	system.perspective.sendMessage("CtrlLeft_Pressed", scope="session", sessionId=page.session.props.id, pageId=page.id)

```

[Conrol] ArrowRight

```python
def onKeyEvent(page, event):
	system.perspective.sendMessage("CtrlRight_Pressed", scope="session", sessionId=page.session.props.id, pageId=page.id)

```

Table \> Configure Scripts \> Message Handlers:  
CtrlRight\_Pressed:

```python
def onMessageReceived(self, payload):
	editingCell = self.custom.editingCell
#	system.perspective.print("custom.editingCell: ")
#	system.perspective.print(editingCell)
	
	if editingCell.row != "" and editingCell.column != "":
		row = editingCell.row
		column = editingCell.column
		# begin updating column
		if column != self.props.columns[-1].field:
			# If we're not yet at the last column
			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
				self.props.editingCell.row = row
	
#	system.perspective.print("props.editingCell: ")
#	system.perspective.print(self.props.editingCell)

```

```
CtrlLeft_Pressed:

```

```python
def onMessageReceived(self, payload):	
	editingCell = self.custom.editingCell
#	system.perspective.print("custom.editingCell: ")
#	system.perspective.print(editingCell)
	
	if editingCell.row != "" and editingCell.column != "":
		row = editingCell.row
		column = editingCell.column
		# begin updating column
		if column != self.props.columns[2].field:
			# If we're not yet at column 2 (the first two columns are not editable)
			current_column_index = -1
			for i in range(len(self.props.columns)):
				if self.props.columns[i].field == column:
					current_column_index = i
			system.perspective.print(current_column_index)
			if current_column_index == -1:
				raise ValueError("Unable to locate current column index!")
			else:
				self.props.editingCell.column = self.props.columns[current_column_index - 1].field
				self.props.editingCell.row = row
	
#	system.perspective.print("props.editingCell: ")
#	system.perspective.print(self.props.editingCell)

```
