Repeater Changing instance parameters

Within a popup window I have a template repeater. Depending on tag that is used for the popup I could have anywhere from 0-50+ instances in this repeater.

I have a script that scans the appropriate areas in the tag and generates the dictionary list to fill in the "instances" with the appropriate parameters.

below is an example of an instances list
For this "Active" can change state at any time and Alarm Type should change based on a tab selection within that popup.

If these were fixed # instances I could do a property binding on each item that I need to update after the instances are loaded.

Is there a way to add the property binding to the instance build?

For example here are my instances

[
  {
    "Active": true,
    "OutputDBID": 10001,
    "OutputPLC": 1,
    "BitMask": 4,
    "AlarmType": 3
  },
  {
    "Active": true,
    "OutputDBID": 10002,
    "OutputPLC": 1,
    "BitMask": 7,
    "AlarmType": 3
  },
  {
    "Active": true,
    "OutputDBID": 10003,
    "OutputPLC": 1,
    "BitMask": 15,
    "AlarmType": 3
  }
]

Here is property binding I would want on every "Active"

 }
  "type": "property",
  "config": {
    "path": "this.custom.SelectedActiveSD"
  }

and property binding on every "AlarmType"

{
  "type": "property",
  "config": {
    "path": "this.custom.ActiveSelected"
  }
}

Currently when it initially loads everything shows correct but if either of the values that I am showing property bindings changes then the instance list doesn't update...

I guess the other thing I could do is put a property change script on the 2 custom parameters shown above to force update the instance list... That feels more demanding on system though.

Just for reference here is my script that generates my dict list for the instances.

def outputList(AlarmType, Active, tagPath):
	tags = system.tag.browse(tagPath +'/Database Actions')
	tagPaths =[]
	result = []
	fullList = []
	for tag in tags:
		basePath =  str(tag["fullPath"])
		path = basePath + "/Output Bit Mask"
		tagPaths.append(path)
		path = basePath +"/Output PLC"
		tagPaths.append(path)
		path = basePath + "/Output DBID"
		tagPaths.append(path)
	values = system.tag.readBlocking(tagPaths)
	for value in values:
		fullList.append(value.value)
	valueList = [fullList[i: i+3] for i in range(0, len(fullList), 3)] 
	for output in valueList:
		BitMask = output[0]
		OutputPLC = output[1]
		OutputDBID = output[2]
		if OutputDBID >0 and OutputPLC >0:
			result.append({"Active": Active, "AlarmType": AlarmType, "BitMask": BitMask, "OutputDBID": OutputDBID, "OutputPLC": OutputPLC})
	return result

So the active and alarmType are available as custom properties in that popup ?

The solution here is to use a structure binding and include those 2 properties in there, so the binding is reevaluated whenever one of them changes.

Side note, take it or leave it, but here's a refactored version of your script:

from itertools import product

def outputList(alarmType, active, tagPath):
	folders = (tag['fullPath'] for tag in system.tag.browse(tagPath + '/Database Actions'))
	tags = {"Output Bit Mask", "Output PLC", "Output DBID"}

	tagPaths = ("{}/{}".format(f, t) for f, t in product(folders, tags))
	values = [qval.value for qval in system.tag.readBlocking(tagPaths)]
	
	return [
		{
			'Active': active,
			'AlarmType': alarmType,
			'BitMask': bitmask,
			'OutputDBID': dbid,
			'OutputPLC': plc
		} for bitmask, plc, dbid in yourlib.chunks(values, 3) if dbid > 0 and plc > 0
	]

I didn't do much testing on the tag browse part, because I don't have time to build a tag structure that matches the use case, but it should work.

Note that it uses a chunks function, which is a custom one. Here it is:

from itertools import izip_longest as zipl

def chunks(it, size, fval=None):
	"""
	'Chunkify' an iterable.
	Splits 'it' into chunks of size 'size', padding with 'fval' if necessary.
	
	params:
		it (iterable):	the source iterable to split into chunks
		size (int):		the size of the chunks
		fval ():		a value to use for padding if the last chunk's size is less than 'size'
	return:
		an iterator over a list of lists
	
	examples:
	iterable = [1, 2, 3, 4, 5, 6, 7]
	size = 3
	fval = 'x'
	=> [[1, 2, 3], [4, 5, 6], [7, 'x', 'x']]
	
	with size = 4:
	=> [[1, 2, 3, 4], [5, 6, 7, 'x']]
	"""
	return zipl(*[iter(it)]*size, fillvalue=fval)

It's a useful one to have in a custom library.

Also, a few suggestions:

  • don't capitalize variables names (but also stay consistent with the codebase). It's conventionally used for classes:
ThisIsAClass
thisIsAVariable or this_is_a_variable
  • avoid spaces in tag names/paths (and any exotic character actually). Try to make tags paths be valid python identifiers. Makes things easier in the long run
1 Like

Thanks for pointing that out. I have not used that before. That works.

Shorter script works as well, thanks.