def transform(self, value, quality, timestamp):
RouteData = []
# This maps out the list.
for row in value:
RouteData.append({
"DeviceID": row["DEVICE_ID"],
"DeviceName": row["DEVICE_NAME"],
"DestinationSelected": row["CHECKBOX"]
})
return RouteData
I am able to everything from the Table and place it in a Custom Property. What I want to do is be able to only append the ones that have DestinationSelected checked.
I am guessing I would need an if then statement but need some help.
def transform(self, value, quality, timestamp):
# This maps out the list.
return [{'DeviceID':row['DEVICE_ID'],'DeviceName':row['DEVICE_NAME'],'DestinationSelected':row['CHECKBOX']} for row in value if row['CHECKBOX']]
This will require you to keep track of when they're selected. Doing this in a transform won't be enough, as far as I can tell there's no way to tell which one was selected first.
You could build your custom prop using click events on the table, appending/removing items to it every time something is selected/unselected.
I would probably recommend that you use the onEditCellCommit event of the table and then use a script similar to this:
if event.column == 'CHECKBOX':
routeData = self.view.custom.RouteData
dataItem = self.props.data[row]
if event.value:
if not dataItem in routeData:
routeData.append(dataItem)
else:
if dataItem in routeData:
routeData.remove(dataItem)
self.view.custom.RouteData == routeData
NOTE: I haven't tested this, so no guarantee, but I think it shows the basic principal. Also, I have not modified the keys here, which will facilitate the remove operation, and the checks to see if the item exists in the list or not. You can change them, but you will need to manually check each value of an item to see if the items are actually the same, or I suppose at least the DeviceID if that is all that matters as far as duplication goes.
Perhaps, @pascal.fragnoud or @bkarabinchak.psi have a magic python trick to make that is not quite so ugly, I couldn't think of one.
Column = event.column
Row = event.row
Value = event.value
self.props.data[self.props.selection.selectedRow].CHECKBOX = Value
system.perspective.print(Column)
system.perspective.print(Row)
system.perspective.print(Value)
if Column == 'CHECKBOX':
RouteTable = self.custom.RouteData
RouteData = self.props.data[Row]
system.perspective.print(RouteData)
if Value:
if not RouteData in RouteTable:
system.perspective.print("Route Removed.")
RouteTable.remove(RouteData)
else:
if RouteData in RouteTable:
system.perspective.print("Route Removed.")
RouteTable.remove(RouteData)
self.custom.RouteData == RouteTable
I took your snippet and got the Append to work fine, but even when I unchecked it it would not remove it.
So I left some duplicate routes in the table and moved the remove so I could see any errors. What you say though makes a ton of sense. I am wondering if using two buttons with this would be easier than just the Checkbox in the Table.
I'm wondering if this has something to do with the fact that you're storing the selected property too...
I'll set up a test and try it myself, see if I can get you a working solution.
I notice that in your script you are trying to remove the selection in both cases. One of them should be an append. You say you were able to get the append to work, but I don't see an append in this script.
Try this, it only looks at the Device ID for equality (similar to how a Primary Key in a database works).
if event.column == 'CHECKBOX':
routeData = self.view.custom.RouteData
rowData = self.props.data[row]
if event.value and not any(rowData['DEVICE_ID'] == route['DEVICE_ID'] for route in routeData):
routeData.append(rowData)
else:
routeData = [route for route in routeData if route['DEVICE_ID'] != rowData['DEVICE_ID']]
self.view.custom.RouteData == routeData
And, @pascal.fragnoud the script looks much nicer without the unneeded nested conditions.
So, I'm not quite sure why, but I couldn't get remove to work...
So I used pop instead:
def runAction(self, event):
row = self.props.data[event.rowIndex]
row.selected ^= True
if not row.selected:
self.custom.data.append({'label': row['label'],'value': row['value']})
else:
idx = next(i for i, d in enumerate(self.custom.data) if d.label == row.label)
self.custom.data.pop(idx)
I put this on a onRowClick event, and toggle the selected column with row.selected ^= True.
I do this partly because this way you can click any column, not just the selected one, but mostly because clicking checkboxes in tables is a pain in the ass: gotta click several times to get to interact with them. This fixes that.
edit:
note that if for some reason the row isn't in the list when you deselect it in the table, you'll get a StopIteration error. This shouldn't happen, as long as you only add and remove items from the list by clicking on the table.
If you want to prevent errors, wrap the idx assignation in a try/except block.
It says, that rowIndex is the row index as it is represented in the current visible data. I take that to mean that it isn't always 1:1 to the index in self.props.data.
@lrose This did work. I will see if I can create something that will remove it if it sees it in the list.
Column = event.column
Row = event.row
Value = event.value
self.props.data[self.props.selection.selectedRow].CHECKBOX = Value
system.perspective.print(Column)
system.perspective.print(Row)
system.perspective.print(Value)
if Column == 'CHECKBOX':
routeData = self.custom.RouteData
rowData = self.props.data[Row]
if Value and not any(rowData['DEVICE_ID'] == route['DEVICE_ID'] for route in routeData):
routeData.append(rowData)
else:
routeData = [route for route in routeData if route['DEVICE_ID'] != rowData['DEVICE_ID']]
self.custom.RouteData == routeData
Error running action 'component.onRowClick' on View/Recipe/Batching@D/root/LeftContainer/DestinationContainer/TableContainer/ScrollContainer/Table: Traceback (most recent call last): File "function:runAction", line 3, in runAction AttributeError: 'com.inductiveautomation.perspective.gateway.script' object has no attribute 'selected'
row = self.props.data[event.rowIndex]
row.selected ^= True
if not row.selected:
self.custom.RouteData.append({'DeviceID': row['DEVICE_ID'],'DeviceName': row['DEVICE_NAME']})
else:
idx = next(i for i, d in enumerate(self.custom.RouteData) if d.DeviceID == row.DEVICE_ID)
self.custom.RouteData.pop(idx)