# Best Way to Return Data from Vision Popup

**URL:** <https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912>\
**Category:** Ignition\
**Tags:** ignition81, vision\
**Created:** [July 8, 2024, 5:49pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912 "2024-07-08T17:49:41Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Brandon\_Peterson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/brandon_peterson/32/32960_2.png) [@Brandon\_Peterson](https://forum.inductiveautomation.com/u/Brandon_Peterson)\
**Post date:** [July 8, 2024, 5:49pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/1 "2024-07-08T17:49:41Z")

</div>

I have a simple "comments" button popup I want to get data back from, and I don't know the best way to do this.

I have a template repeater on the main window, and each template instance has a "edit comments" button on it. When I press that, it opens a new popup window for the user to put their comments in. I don't know what to put in the "actionPerformed" script for the "submit" button on the popup.

My first guess would be a message handler, but Vision components can't receive messages like Perspective components can. How should I go about this?

```python
project = system.project.getProjectName()
messageHandler = 'myMessageHandler'
payload = {
	'templateID': event.source.parent.templateID,
	'comments': event.source.parent.comments
}
clientSessionId = system.util.getClientId()

system.util.sendMessage(project, messageHandler, payload, scope='C', clientSessionId=clientSessionId)
system.nav.closeParentWindow(event)

```

_I have already thought of `system.gui.inputBox`, but the text is too small. A client tag dataset seems most logical to me, but it just feels like a messy way to do a simple thing._

---

<div class="post-metadata">

**Author:** ![michael.flagler](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/michael.flagler/32/26272_2.png) [@michael.flagler](https://forum.inductiveautomation.com/u/michael.flagler)\
**Post date:** [July 8, 2024, 6:01pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/2 "2024-07-08T18:01:29Z")

</div>

What are you doing with the comment? If it's being written to a database or a tag, why not do it directly in your custom popup window?

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [July 8, 2024, 6:02pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/3 "2024-07-08T18:02:25Z")

</div>

In vision, you would get a reference to the window using: `system.gui.getWindow()` and then write to a property to hold the data.

---

<div class="post-metadata">

**Author:** ![Brandon\_Peterson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/brandon_peterson/32/32960_2.png) [@Brandon\_Peterson](https://forum.inductiveautomation.com/u/Brandon_Peterson)\
**Post date:** [July 8, 2024, 6:04pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/4 "2024-07-08T18:04:09Z")

</div>

I want the whole screen to be like a form where a "submit" button enters data from all the template instances. I don't want any database writing to happen until that button is pressed. That's what made sense to me. No undo-redo, just a hard submit with an "are you sure?" attached.

---

<div class="post-metadata">

**Author:** ![Brandon\_Peterson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/brandon_peterson/32/32960_2.png) [@Brandon\_Peterson](https://forum.inductiveautomation.com/u/Brandon_Peterson)\
**Post date:** [July 8, 2024, 6:05pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/5 "2024-07-08T18:05:49Z")

</div>

Okay, so that seems to solve the template to window gap, but what about communicating from the popup window to the main window? `system.gui.getOpenedWindows()`?

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [July 8, 2024, 6:12pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/6 "2024-07-08T18:12:32Z")

</div>

`system.gui.getOpenedWindows()` returns all of the currently opened windows. Since, presumably you already know the name of the window, and you know that it will be open, then there is no need to use that, just get a reference to the window.

---

<div class="post-metadata">

**Author:** ![Brandon\_Peterson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/brandon_peterson/32/32960_2.png) [@Brandon\_Peterson](https://forum.inductiveautomation.com/u/Brandon_Peterson)\
**Post date:** [July 8, 2024, 6:20pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/7 "2024-07-08T18:20:13Z")

</div>

Is the "name" of the window just the name of the window component definition?

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

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [July 8, 2024, 6:21pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/8 "2024-07-08T18:21:31Z")

</div>

Yes.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 8, 2024, 6:32pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/9 "2024-07-08T18:32:25Z")

</div>

With folder names, just like you'd use with `system.nav.openWindow()`.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [July 8, 2024, 6:47pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/10 "2024-07-08T18:47:49Z")

</div>

You can right click on the window, and select copy path and get exactly what you need.

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [July 9, 2024, 12:29pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/11 "2024-07-09T12:29:54Z")

</div>

Instead of searching for windows to pass data to, wouldn't it be simpler to just use a client tag?

---

<div class="post-metadata">

**Author:** ![bschroeder](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bschroeder/32/13260_2.png) [@bschroeder](https://forum.inductiveautomation.com/u/bschroeder)\
**Post date:** [July 9, 2024, 12:44pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/12 "2024-07-09T12:44:09Z")

</div>

I've used something like this as well when having a generic popup to do things.

> [@Passing reference to component to a window](https://forum.inductiveautomation.com/t/passing-reference-to-component-to-a-window/59368/3):
>
> I’m copy pasting my personal notes, but perhaps you’ll find them useful. Here: Using callbacks in Vision Window - Caller Can be in the script of a button. The callback can reference event or self depending on the context in which this script is running (within a custom method, or a component event). def callback(): print 'hey' window = system.nav.openWindowInstance('Popups/popupName') window.putClientProperty('callback', callback) system.nav.centerWindow(window) Popup - Callback windo…

Basically, you have a function on your window that you would pass to the popup, and the popup would call that function before closing to either pass data back, or provide a confirmation etc...

---

<div class="post-metadata">

**Author:** ![Brandon\_Peterson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/brandon_peterson/32/32960_2.png) [@Brandon\_Peterson](https://forum.inductiveautomation.com/u/Brandon_Peterson)\
**Post date:** [July 9, 2024, 12:49pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/13 "2024-07-09T12:49:27Z")

</div>

I think this is what I'm looking for!

Here's the situation I have, in case I wasn't super clear about it before:  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/e/f/ef53e6f11a613d8b9e6a831ef4b9d4f749aa744c.png)

I'm hoping I can use closure to create a reference to a property in the template instance ("comment" property), put that in a callback function, use the suggested method to pass that function to the popup, then call it once the popup returns.

This is making sense. I'll give it a try!

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [July 9, 2024, 12:51pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/14 "2024-07-09T12:51:48Z")

</div>

I tend to only use tags when I need the data to be persistent across startup. But yes, a client tag would also work here.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 9, 2024, 1:16pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/15 "2024-07-09T13:16:18Z")

</div>

> [@Brandon\_Peterson](#):
>
> can use closure to create a reference to a property

Not closures, no, but the script that opens that popup can use the returned window object's `.putClientProperty()` method to store an arbitrary object reference in the popup. The popup's save action would use the window's matching `.getClientProperty()` to retrieve the original component, to which it can then assign results to properties.

Unlike client tags, this approach scales to many popup windows, even those created with `.openWindowInstance()`.

---

<div class="post-metadata">

**Author:** ![Brandon\_Peterson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/brandon_peterson/32/32960_2.png) [@Brandon\_Peterson](https://forum.inductiveautomation.com/u/Brandon_Peterson)\
**Post date:** [July 9, 2024, 3:28pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/16 "2024-07-09T15:28:11Z")

</div>

I got it! But I want to make sure I'm not doing anything dangerous (not thread-safe) or unnecessary. Do I need the `invokeLater` call?

### Template Open Popup Button

```py
from functools import partial

template = event.source.parent

def setNewComment(newComment):
	template.comment = newComment

def updateComment(newComment):
	'''Callback function to update the comment property on the template from the popup context'''
	
	system.util.invokeLater(partial(setNewComment, newComment))

window = system.nav.openWindow('Path/To/MyPopup', {'comments': event.source.parent.comment})
window.putClientProperty('updateComment', updateComment)
system.nav.centerWindow(window)

```

### Popup OK button

```py
newComment = event.source.parent.comments
window = system.gui.getParentWindow(event)
updateComment = window.getClientProperty("updateComment")
updateComment(newComment)
system.nav.closeParentWindow(event)

```

---

<div class="post-metadata">

**Author:** ![michael.flagler](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/michael.flagler/32/26272_2.png) [@michael.flagler](https://forum.inductiveautomation.com/u/michael.flagler)\
**Post date:** [July 9, 2024, 4:31pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/17 "2024-07-09T16:31:11Z")

</div>

While I'll admit first off that I haven't tested your code, but couldn't you just remove both the `setNewComment` function and `from functools import partial` and change the `updateComment` function as follows:

```python
def updateComment(newComment):
	template.comment = newComment

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 9, 2024, 4:33pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/18 "2024-07-09T16:33:03Z")

</div>

> [@Brandon\_Peterson](#):
>
> Do I need the `invokeLater` call?

Not when the script is already running in the foreground (like a save button's actionPerformed event).

I wouldn't put a function in the window client property for _ **simple** _ tasks. Just put the target component itself.

```python
...
window.putClientProperty('commentTemplate', template)

```

Then:

```python
...
template = window.getClientProperty('commentTemplate')
template.comment = newComment

```

---

<div class="post-metadata">

**Author:** ![Brandon\_Peterson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/brandon_peterson/32/32960_2.png) [@Brandon\_Peterson](https://forum.inductiveautomation.com/u/Brandon_Peterson)\
**Post date:** [July 9, 2024, 5:38pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/19 "2024-07-09T17:38:47Z")

</div>

### Template Open Popup Button

```py
template = event.source.parent
window = system.nav.openWindow('Path/To/MyPopup', {'comments': template.comment})
window.putClientProperty('commentTemplate', template)
system.nav.centerWindow(window)

```

### Popup OK Button

```py
newComment = event.source.parent.comments
window = system.gui.getParentWindow(event)
template = window.getClientProperty('commentTemplate')
template.comment = newComment #<-- Fails

```

I'm getting this error:

```python
com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last):
  File "<event:actionPerformed>", line 4, in <module>
AttributeError: 'com.inductiveautomation.factorypmi.application.com' object has no attribute 'comment'

```

Presumably because the property is now private in this context.

```py
print(template.isPropertyDefined('comment'))
print(template.isPropertyDefinedAndPublic('comment'))
# Prints:
# True
# False

```

Should I just switch back to the function closure method then, since that worked?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 9, 2024, 6:36pm UTC](https://forum.inductiveautomation.com/t/best-way-to-return-data-from-vision-popup/92912/20 "2024-07-09T18:36:37Z")

</div>

Hmmm, this is one of the `PyComponentWrapper` gotchas, where jython won't recognize custom properties nor component custom methods.

If you can, install my Integration Toolkit to fix that for all cases. See more here, including a non-module solution:

> [@Why can't custom properties and methods be accessed from a component that is obtained using SwingUtilities.getAncestorOfClass?](https://forum.inductiveautomation.com/t/why-cant-custom-properties-and-methods-be-accessed-from-a-component-that-is-obtained-using-swingutilities-getancestorofclass/78606/2):
>
> Custom properties are added to the java standard jython conversion by IA's PyComponentWrapper. For a complete discussion, read this entire topic: TL/DR: Install my Simulation Aids Integration Toolkit module to magically fix this, everywhere in Ignition. There is no other solution until IA eventually does this first party. See below.
