# How to Close a Perspective Popup Asynchronously After a Delay in Ignition?

**URL:** <https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869>\
**Category:** Ignition\
**Tags:** ignition81, perspective\
**Created:** [December 16, 2024, 11:06am UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869 "2024-12-16T11:06:33Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![sibabrat\_swain](https://avatars.discourse-cdn.com/v4/letter/s/a88e57/32.png) [@sibabrat\_swain](https://forum.inductiveautomation.com/u/sibabrat_swain)\
**Post date:** [December 16, 2024, 11:06am UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/1 "2024-12-16T11:06:33Z")

</div>

Hello everyone,

I am working on an Ignition project using Perspective, and I want to create a toast notification using a popup. The popup should automatically close after a certain delay (e.g., 5 seconds) without blocking the main thread. Here's what I've tried so far:

1. **Opening the Popup** : I'm using `system.perspective.openPopup`, and that works perfectly.
2. **Closing the Popup After Delay**

- tried using `system.util.invokeAsynchronous` to create a separate thread and used `time.sleep` to add a delay.
- After the delay, I called `system.perspective.closePopup` to close the popup.

However, this doesn't seem to work as expected, but the `closePopup` function does not execute or fails silently. Here's the relevant part of my code:

```python
import system
import time

class ToastManager:
    @staticmethod
    def open_toast(popup_id, view_path, params=None, duration=5):
        # Open the popup
        system.perspective.openPopup(popup_id, view_path, params)

        # Asynchronous task to close the popup after a delay
        def async_task():
            time.sleep(duration) # Wait for the specified duration
            system.perspective.closePopup(popup_id) # Attempt to close the popup

        system.util.invokeAsynchronous(async_task)

```

```python
ToastManager.open_toast("myToastPopup", "PopupViews/MyToastView", {"message": "Hello, world!"}, 5)

```

The popup opens successfully, but the `closePopup` function does not work. If I call the `async_task` function directly it closes the popup with delay. But with `invokeAsynchronous` it does not close or throw any error.

Where I am getting wrong on this? Seems like the invoke `invokeAsynchronous` is not working. Where is this going wrong?

**Platform**  
**Ignition Platform** `8.1.30 (b2023071408)`

_I only want to close the popup using project library scripting._

### Questions

1. Is it possible to call `system.perspective.closePopup` from an asynchronous thread using `invokeAsynchronous`?
2. Do I need to use a different method to close the popup from a separate thread?
3. Is there a recommended way to achieve this functionality in Ignition Perspective?

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [December 16, 2024, 11:46am UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/2 "2024-12-16T11:46:08Z")

</div>

Sleep = bad.  
Just add a timer on the view itself which closes itself. Set the time on load to a custom prop, and add a custom prop to get the difference in seconds between now and the first load prop and compare to your open seconds. If true, use an on change script to close the popup passing in "" as the view name

---

<div class="post-metadata">

**Author:** ![sibabrat\_swain](https://avatars.discourse-cdn.com/v4/letter/s/a88e57/32.png) [@sibabrat\_swain](https://forum.inductiveautomation.com/u/sibabrat_swain)\
**Post date:** [January 5, 2025, 4:27pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/3 "2025-01-05T16:27:34Z")

</div>

I like your idea but Can you tell me how to check the condition in every seconds? Do I need to set a CRON job to check the condition and close the popup?

In Other words how to set a timer in the view?

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [January 5, 2025, 5:07pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/4 "2025-01-05T17:07:54Z")

</div>

- In Project Browser, select the root of your view.
- In Perspective Property Editor scroll down to CUSTOM.
- Create a new custom property `startTime`.
  - Create an expression binding on `startTime` with the expression, `now(0)`. This will fire once when the popup opens and save the current timestamp in the custom property.

- Create a second tag, `timeout`.
  - Add an expression binding,  
`(now(1000) - {this.custom.startTime}) > 5000`  
This will evaluate every 1000 ms and will return `true` when the popup has been open for 5000 ms.

- Right-click on `custom.timeout` and select Edit Change Script. Add the script,

```python
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	if currentValue.value:
		system.perspective.closePopup("")

```

Tips:  
`now(0)` → Runs once on load.  
`now()` → Runs at the default scan rate - typically 1000 ms.  
`now(4321)` → Runs every 4321 ms.

---

<div class="post-metadata">

**Author:** ![jlandwerlen](https://avatars.discourse-cdn.com/v4/letter/j/bc8723/32.png) [@jlandwerlen](https://forum.inductiveautomation.com/u/jlandwerlen)\
**Post date:** [January 5, 2025, 5:09pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/5 "2025-01-05T17:09:16Z")

</div>

Here's a crude example that changes label text, paste the JSON into a view.

```python
{
  "custom": {},
  "params": {},
  "props": {},
  "root": {
    "children": [
      {
        "events": {
          "component": {
            "onActionPerformed": {
              "config": {
                "script": "\tself.getSibling(\"Label\").custom.textTime \u003d system.date.now()"
              },
              "scope": "G",
              "type": "script"
            }
          }
        },
        "meta": {
          "name": "Button"
        },
        "position": {
          "height": 34,
          "width": 80,
          "x": 133,
          "y": 140
        },
        "type": "ia.input.button"
      },
      {
        "custom": {
          "textTime": {
            "$": [
              "ts",
              192,
              1736096810562
            ],
            "$ts": 1736096810562
          }
        },
        "meta": {
          "name": "Label"
        },
        "position": {
          "height": 32,
          "width": 234,
          "x": 262,
          "y": 142
        },
        "propConfig": {
          "custom.textReset": {
            "binding": {
              "config": {
                "expression": "(secondsBetween({this.custom.textTime}, now()) \u003e\u003d 5)"
              },
              "type": "expr"
            },
            "onChange": {
              "enabled": null,
              "script": "\tif currentValue.value:\n\t\tself.props.text \u003d \u0027Text reset\u0027\n\telse:\n\t\tself.props.text \u003d \u0027Button was pushed\u0027"
            }
          }
        },
        "props": {
          "text": "Text reset"
        },
        "type": "ia.display.label"
      }
    ],
    "meta": {
      "name": "root"
    },
    "type": "ia.container.coord"
  }
}

```

---

<div class="post-metadata">

**Author:** ![sibabrat\_swain](https://avatars.discourse-cdn.com/v4/letter/s/a88e57/32.png) [@sibabrat\_swain](https://forum.inductiveautomation.com/u/sibabrat_swain)\
**Post date:** [January 5, 2025, 5:23pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/6 "2025-01-05T17:23:46Z")

</div>

> [@sibabrat\_swain](#):
>
> `invokeAsynchronous`

This will work but I don't want to use tag browser for this operation due to architectural constraints. That's my last hope. I can use similar condition which You have given directly inside my class and check until the condition meets.

But I am more curious why the `invokeAsynchronous` does not execute the `async_task` in my above example? If I Call the `async_task()` directly it works. I mean it waits until the duration and closes the popup. But not with `invokeAsynchronous`. For toast implementation I don't want to make things complicate if the `invokeAsynchronous` works.

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [January 5, 2025, 5:26pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/7 "2025-01-05T17:26:31Z")

</div>

> [@sibabrat\_swain](#):
>
> ... but I don't want to use tag browser for this operation ...

My solution does not use tags or the tag browser.

---

<div class="post-metadata">

**Author:** ![sibabrat\_swain](https://avatars.discourse-cdn.com/v4/letter/s/a88e57/32.png) [@sibabrat\_swain](https://forum.inductiveautomation.com/u/sibabrat_swain)\
**Post date:** [January 5, 2025, 5:29pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/8 "2025-01-05T17:29:57Z")

</div>

I see, I understood wrongly. But can you help me understand the previous reply please?

---

<div class="post-metadata">

**Author:** ![Transistor](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/transistor/32/3380_2.png) [@Transistor](https://forum.inductiveautomation.com/u/Transistor)\
**Post date:** [January 5, 2025, 5:34pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/9 "2025-01-05T17:34:05Z")

</div>

If you are referring to post #6, then I don't know. I've had no reason to use Toast or create a class for such a simple task. The expression bindings and change events are simple, built-in and use resources efficiently.

---

<div class="post-metadata">

**Author:** ![sibabrat\_swain](https://avatars.discourse-cdn.com/v4/letter/s/a88e57/32.png) [@sibabrat\_swain](https://forum.inductiveautomation.com/u/sibabrat_swain)\
**Post date:** [January 5, 2025, 5:46pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/10 "2025-01-05T17:46:49Z")

</div>

> [@Transistor](#):
>
> startTime

I have implemented a class to enhance the code’s reusability. Although it is not a simple popup, we are utilizing popups for the toast functionality. Regrettably, there is no alternative to popups in Ignition. Nevertheless, I am employing toast to display information throughout the application. I have provided a snippet of my requirements for this question. In actuality, the requirements are quite intricate.

If you can see my first reply to your answer and help me understand why the `invokeAsynchronous` does not able to execute the `async_task()`. That will be helpful.

 ![Screenshot (52)](https://us1.discourse-cdn.com/inductiveautomation/original/3X/f/6/f6fbc7cf69848dd0671f669a9c09a467221688b8.png)

---

<div class="post-metadata">

**Author:** ![jlandwerlen](https://avatars.discourse-cdn.com/v4/letter/j/bc8723/32.png) [@jlandwerlen](https://forum.inductiveautomation.com/u/jlandwerlen)\
**Post date:** [January 5, 2025, 6:46pm UTC](https://forum.inductiveautomation.com/t/how-to-close-a-perspective-popup-asynchronously-after-a-delay-in-ignition/99869/11 "2025-01-05T18:46:05Z")

</div>

Did you see my example? While it isn't a popup it shows a timer example, instead of changing text you close the popup and instead of the button starting the timer it starts when you open the popup.
