Perspective Table Dropdown Cell View Problem

Hi all,

I am trying to populate a dropdown cell in a perspective table component with a viewPath, viewParams, and render=“view” set in a particular column in the table.props.columns property.

However, i’d like this dropdown to be able to register the particular row/col that it is in so once edited, it can send a value to the correct place based on row/col. The cell commit script does not fire, unless there is some way to hook this cell view to the table to make it work in that manner. Any ideas?

Additionally, is it possible to pre-populate the dropdown in the cell based on row/col? I only know its association with column index/name since that is where it is defined. My workaround for this is to use a message handler to initially populate all of those views based on the rows they reside in.

Cheers,
Roger

I have essentially the same question, but more fundamentally: how does one embed a dropdown in a perspective table for a given column and how, as the original poster asked, do I access the updated value of the dropdown?

I can answer the former for you - on the chart component, there is a property called columns (self.props.columns) which is a list that holds multiple fields, one per item, e.g.

props.columns[0]
props.columns[1]

props.columns[ncols]

You can assign the field, the render type, the viewPath, and viewParams inside whichever column you need the dropdown at. You’ll have to assign a dropdown component inside a view that will be passed into the viewPath/viewParams parameters, e.g.

props.columns[0].field = “Column Name”
props.columns[0].render = “view”
props.columns[0].viewPath = “path/to/dropdown”
props.columns[0].viewParams = {“value”:1}
etc.

This would give you a view containing a dropdown in column 0 with the column named “Column Name” and inserted parameter “value” with a value of 1.

But honestly, it could be easier to just use a flex repeater and message handlers to get better output than embedding a view in a table - I can’t find any way to get the output from it without knowing what rowIndex it came from.

Cheers,
Roger

Since 8.0.2 there is a implicit rowData property passed to the view configured for a column. This property contains not only the configured column but the complete row data. So if your row has a unique id property, that property is available in your view and can be used e.g. in a OnActionPerformed event of your dropdown.

1 Like

Hi,

Sorry for the delay. Did you manage resolve your issue? What @chi suggested should work. Let us know. Thanks!

-Y

How does one access the implicit rowData property in a binding?

I.e. if I wanted to bind an input parameter for the viewParams = {rowData.value} (or whatever its called) then what would I enter to do this?

image

Thanks,
Keith G.

1 Like

I’m missing something on how the new rowData feature works. rowData.value seems to be the value of the given column the expression is evaluated, which is all fine and good but I also need to pass my subview a key for the row to be able to make an update on change. My key column is called id, is that accessible through rowData (or another way)?

What am I missing?

1 Like

From the manual for rowData:

Used to map parameters on a view cell to an entire row of data. The view must have a rowData object input parameter, with sub values that match the names of the columns. Then add the new view to the props.columns.0.viewPath property, and the input parameter as the props.columns.0.field property.

The rowData parameter of the view contains all data from your row. So if your row has an column 'id', the value of this column will be in the row data object with the key 'id'.

rowData

1 Like

It might be worth noting that (at least v8.0.3) the rowData object is not a dictionary or JSON object. Rather it is a “<type ‘com.inductiveautomation.perspective.gateway.script.PropertyTreeScriptWrapper$MapWrapper’>”. Which cannot be manipulated in the same way as the former two (yet at least).

You’ll have to use code similar like this to construct a copy of the rowData as a dictionary.

#import the copy library
	import copy
#recreate the rowdata of the current row as a dictionary
	#empty dictionary to be filled with the RowData of the current Row
	rowData = {}
	#temporary variable to hold the raw rowData
	d = self.view.params.rowData
	#loop through the raw rowdata to recreate it as a dictionary.
	for key in d:
		#the key has to be copied otherwise every single key will be the same in the new dictionary
		rowData[key] = copy.copy(d[key])
		
	#the Id of the currently selected record	
	id = rowData[uniqueColumn]

There’s most likely a more efficient way, but at least this code works.

The simple way is: self.view.params.rowData.uniqueColumn.
Ignition wraps the properties in a ScriptWrapper to make them accessible this way. You can also use the 'Browse Properties' button in the top right corner of the script editor.

You can also use the ‘Browse Properties’ button in the top right corner of the script editor.

Not if your rowData isn't set in stone. In the use case my code was from the rowData was constantly different.

I was also unable to access the rowData in the way you described. It might be because of my version of Ignition however (8.0.3).

There are a lot of incomplete pieces here that I can’t seem to assemble.
There is a table which has columns.
The column is set to render using a view which is a drop-down.

When it runs, the view beautifully displays the values in the drop down.
How do I connect the data selected in the drop-down view to the table?

The onEditCellCommit event fires just fine for cells that are edited directly but is NOT fired when the value of the drop-down in the rendering view is changed.

I have also discovered that if I turn on enableRowSelection, the view is ignored and the edit takes place directly in the cell and yes, the onEditCellCommit fires but, the functionality of the drop-down view is lost.

I’m sure that there’s just one simple piece I’m missing but I’m not good at finding Waldo.
In order to make these work together:
What script/binding do I need to put into the drop-down view?
What script/binding do I need to put into the table?
[ it would be nice to select the row but I’ll give it up to have drop-down functionality in a table. ]

You'll want to pass the value of the cell onto your dropdown view as a parameter. The options will be a dictionary where the key corresponds to the original value so I can show the right option.

If you want to modify that value, assuming you're connected to a database, you just let an event on your dropdown view handle the update query. If you're not connected to a database, as long as you bidirectionally bind the value to the parameter in your column prop and the parameter to the selected option in your dropdown view, it should change.

You'll also want to make sure that column cannot be edited like the other's, since it'll try to edit the underlying textbox instead of the dropdown.

Sorry guys I’m totally new to this topic, but I want to use dropdown inside a table column. The explanations above are too detail for me to understand. If I can get some screenshots, I will be grateful.
Thanks.

The columns prop on your table:


Note that viewpath is set to the view containing my dropdown. Make sure to set your view params, so your dropdown has all the necessary information to make changes.
image

The Params on my dropDownView
image
Because I’m going to update a database all my params are set to input, you can tell by the arrows, but depending on what you want to do you might want to change that.
I bind the options prop to the options param I gave the view, then there is one script on the dropdown itself.

	#--- Prerequisites
	#import the copy library
	import copy
	
	#name of the current table
	tableName = self.view.params.TableName
	#name of the current column
	colName = self.view.params.Column
	#the new value
	newValue = self.props.value
	#the uniquecolumn/Id column
	uniqueColumn = self.view.params.idCol
	
	#recreate the rowdata of the current row as a dictionary. (This has to be done, because even though the string output of the rowdata parameter looks like a dictionary, it is a MapTree and can't, yet, be approached as though it is a dictionary)
	#empty dictionary to be filled with the RowData of the current Row
	rowData = {}
	#temporary variable to hold the raw rowData
	d = self.view.params.rowData
	#loop through the raw rowdata to recreate it as a dictionary.
	for key in d:
		#the key has to be copied otherwise every single key will be the same in the new dictionary
		rowData[key] = copy.copy(d[key])
		
	#the Id of the currently selected record	
	id = rowData[uniqueColumn]
#---END
	
#--- Update the table
	# Create our query and arguments. The extension function gives us a colName variable,
	# which we can use in our query. The query will then take two arguments.
	# The value that we are updating and the id of the row we edited.
	query = "UPDATE "+tableName+" SET %s = ? WHERE %s = ?" % (colName, uniqueColumn)
	args = [newValue, id]
	 
	# Run the query with the specified arguments.
	rowsAffected = system.db.runPrepUpdate(query, args)
#---END

Note that I’m doing some funky stuff to recreate rowdata, because in my version of ignition it wasn’t passed as a datatype that I could interact with as a dictionary.

2 Likes

I am editing fields of a tag alarm so changing them in the dropdown is difficult, I am exploring the bidirectional bind however I should bind a subelement ("activePipeline" in the screenshot below) of the implicit rowData object:

image

also on the column element where I pass the view parameters the rowData element is implicit so how can I bind to the onchange of the "activePipeline" value?

I do not think you’re going to be able to bidirectionally bind to alarm properties of a tag in this manner. I think you’re far better off getting the alarm data by using system.tag.getConfiguration() and then writing it back using system.tag.configure().

my post was probably not extremely clear but alarms are not the problem and I posted here because I’m using exactly what was suggested before: I am basically editing a table on double click of a cell and this cell is a dropdown view which must on selection return an event to the table view to tell it to update the cell with the dropdown selection.
The table represents fields of a list of alarms which I edit just as you said using system.tag.getConfiguration() and then writing with system.tag.configure() however the problem is the bidirectional binding of a variable which is not returned, what I currently have is a binding as below of the column viewParams:

the dropdown has a onActionPerformed event to set the bidirectional variable:

and here are all the params including the changed_value (notice I tried with rowData as bidirectional as well as other direction combinations but nothing ever worked)

image

hope this clears it up, basically I’m doing what @RadicalRumin suggested I think.

If I am understanding you correctly, you are trying to get a dropdown component within an embedded view in a table’s cell to update the value associated with that particular cell. I, personally, have not had any luck doing this with bidirectional bindings. I would use message handlers to update the cell’s value in the data property of your table instead. I wrote a post here that explains how I would approach it. Hopefully that helps clarify things?

Thank you I opted for the message handler, the bidirectional binding would have been cleaner but apparently it is not feasible at the moment.