Out parameters of a view not updated

I created a perspective view with nothing but a TextField.
The view has a param called "MyOutParm" that is set as an output param **and is bound to the TextField's text property.

I called the view I've just created Subview, and i created a second view, the MainView that is going to use this subview.
I want to show what seems to be a bug in the way MyOutParam is returned when the subview instances are added dynamically.

So in my MainView I added a FlexRepeater with path set to SubView.
Additionally i added an instance of subview via designer. This is for test completeness and infact it works fine.
Then I added a button for adding an instances to FlexRepeater's instance property, a button for setting instances property (so replacing all the instances at once), and here is where the problems arise.

Then, for showing the problem I put a button and a TextArea; when this button is pressed, the content of FlexRepeater's Instances property is display on the TextArea.

The code of Add Instance:

newInstance = {}	
self.getSibling("FlexRepeater").props.instances.append(newInstance)

The code of Replace Instances:

newInstance = {}	
newInstances = []	
newInstances.append(newInstance)
self.getSibling("FlexRepeater").props.instances = newInstances

The code of DisplayFlexrepeaterInsances:

insts = self.getSibling(FlexRepeater).props.instances
self.getSibling(TextArea).props.text = insts

Pressing Add Instance and then the display button, what I get is:

[{"MyOutParam":"initial text","instancePosition":{},"instanceStyle":{"classes":""}},
{"MyOutParam":"initial text"}]

You see that the second item gets correcly created and even if I didn't add MyOutParam when I created it, the param is correcly added by the component.
Adding instnaces always work.
Now, if i click on 'Replace instances', that sets the whole Instances property, and then I click on the display button, what I get is:
[{}]
That is, MyOutParam is not created by the subview.

I bumped into this because I populate instances from database records by binding the instance property of FlexRepeater to a property that conatins a resultset.

res = []
for i in range(0, value.getRowCount()):
	viewParams = {}
	viewParams["id"] = value.getValueAt(i, "ID")
	res.append(viewParams)			
return res

Now I'm considering just clearing the array and adding the new instances, but how to do this when the instance property is set via binding? Seems not possibile, and it may require an other approach, maybe a change script on the origin property.

Use messages to get the data out of the subviews. Have a listener on the parent page then you can handle the data outside of the repeater. Just send any identifying data in the payload. You can use an input parameter in the subviews to hold that identifying data.

Put the system.perspective.sendMessage() method on the subview components and add a Script on the parent page listening for those messages.

I have also encountered this problem with out parameter and FlexRepeaters. This is clearly a bug in the implementation of the FlexRepeater and Inductive Automation should fix it. It still exists on the latest stable version of Ignition as of this writing: 8.1.25.

Workaround

The approach @kyler.kamyszek proposed should work, but it's annoying to have to create message handlers for getting data that should be directly accessible via out parameters. Until this bug is fixed, using message handlers is probably the best workaround.

To reproduce the bug

To illustrate the bug and provide a reproducible example, I've created a view that has a FlexRepeater and another view (subview) that the FlexRepeater uses.

Here's the export: flexrepeater-outparam-bug.zip (9.5 KB)

The top text area takes comma delimited string and splits the string when the button is pressed. The string is split and each piece is used as an in parameter for an object in the FlexRepeater's instances array . The out parameter in the subview is bound to the in parameter value.

This first screenshot is when you first load the view and press the "Split on commas" button. You can see that each subview has an in and an out parameter, and that the FlexRepeater instances each have an in and and out also.

If you add ,c to the string and click "Split on commas" again, you can see that the subview parameters are as expected, but the out parameter is missing from the original two objects in the FlexRepeater instances array. Each of the objects in the instances array should have both an in and an out. Clearly the out binding on the subview was evaluated since it's shown in the Subview Parameters section. It's just that out is no longer present/accessible in in the FlexRepeater instances property.

After digging into this a bit, it was determined that it’s not a bug. What’s happening in both the original post’s ReplaceInstances method and the replication with the “Split on commas” actionPerformed script, is that the instances property is being set to an array that no longer contains the output parameters. The output parameters will not propagate back out from the subview to the Flex Repeater until the value of the output parameter(s) change.

Further workarounds I've found:

Synchronize properties to existing instances

Instead of replacing existing instances in the FlexRepeater, copy properties over to the existing instances. It's quite annoying to have to do this, but if you do it then the out parameters won't disappear. The basic approach was to step through the new array and the existing instances one by one and copying properties from the new one to the existing instances array. If the new array was longer then I'd append instances to the existing instances array. If the new array was shorter, then I'd remove instances from the existing instances array.

This is probably the workaround I'll use in the future.

Remove all instances, then replace the instances

Another workaround is to completely remove all the instances (e.g. assign flexrepeater.props.instances=[]) and then assign the new array values to instances. This workaround was mentioned in another issue.The downside to this approach is that any state held in input components, like text fields, will get wiped out. Also, there may be a brief moment where the view shows all the instances missing.

Force the output to change

When instances are replaced, the out parameters won't be propagated to the new instances unless the value changes. I found that even if I change the input properties, and the output parameter binding is re-evaluated, then the out parameter still won't be present on the flex repeater instance unless the output parameter changes. One such way to force a change is to have a constantly changing value, like a timestamp, be part of the output parameter. In such a case, a single output property could be an object like {"out":"real_out_value", "dummy":1681427822105}.

The out part of the object may never change, but the dummy value does, thus forcing the whole out parameter to change. I only add this workaround for completeness since it would be a very ugly and annoying way of ensuring out parameters are populated.