# Conclusion: The need to dispose of an enhanced view interferes with some third-party integrations

**URL:** <https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554>\
**Category:** Framework Knowledge\
**Created:** [December 10, 2025, 7:26pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554 "2025-12-10T19:26:45Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [December 10, 2025, 7:26pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/1 "2025-12-10T19:26:46Z")

</div>

Hello,

(_Please see the following post_: [Nested custom components issues (Devextreme and Aurelia 2.0 story)](https://discourse.aurelia.io/t/nested-custom-components-issues-devextreme-and-aurelia-2-0-story/6553) ).

I’ve come to the conclusion that the need to dispose of an enhanced view (what’s given to us upon enhancement) interferes with those third-party components that handle their own visibility (in some cases). We may not always receive a DOM-removal event for _children_ of the parent component.

With the Devextreme components, **Popover** , **Popup** , and **Tooltip** , are hidden and shown under the power of the third-party component. This leaves inner enhanced content dangling. Hiding a popup doesn’t provide an opportunity to dispose of inner content, which leaves the controller of the consuming component in an unstable state.

This problem didn’t occur in Aurelia 1.0 because there was no need to dispose of the view. Interestingly, I never had to worry about whether the `view` was going to be available on which to call lifecycle hooks. With Aurelia 2.0, it is possible to have an `enhancedView` on which there is no longer a `deactivate` or `dispose` method.

In Aurelia 1.0, the aforementioned components work fine with enhanced inner content. In Aurelia 2.0, they do not.

**How do we handle this scenario?**

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [December 10, 2025, 8:25pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/2 "2025-12-10T20:25:26Z")

</div>

Normally you wouldnt need to go for dispose unless you are sure its never gonna ve touched again. The error and the behavior you described sounds to me like you are doing dispose rather than normal deactivation. Can you give some pseudo code?

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [December 10, 2025, 9:00pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/3 "2025-12-10T21:00:38Z")

</div>

The code given below was crafted with your help, and it works perfectly for all of the other components in the Devextreme suite (at least, the 33 I’ve wrapped so far). It’s just the **Popover** , **Popup** , and **Tooltip** components that are a problem because of how they handle visibility.

I’ve tried to guard around it by testing first for `enhancedView`, and then for the presence of `deactivate` and `dispose` methods. That eliminates the error, _but causes memory to leak because the inner enhanced content never disposes_.

The big problem here is that the 3 components I pointed out above do not dispatch `dxremove` when the popup is hidden (by the close box, or by clicking outside). So I have no way to hook in.

The `createRenderer` mehod:

```javascript
createRenderer(rawTemplate, renderData, config) {
    // Necessary to avoid a hydration instruction mismatch
    const $template = rawTemplate.cloneNode(true);
    // Place the template into the container the Dx widget provides
    renderData.container.append($template);
   
    const enhancedView = Aurelia.enhance({
      container: config.container,
      host: $template,
      component: {
        data: renderData.model,
      },
    });

    // Register a Dx remove event, dxremove, so we can apply Aurelia conventions to deactivating and disposing of an enhanced view
    // The widget will clean this up itself upon its disposal
    dxEventOn($template, 'dxremove', (e) => {      
      if (!enhancedView) {
        return;
      }

      // This will trigger the tear-down lifecycle hooks of the enhanced view.
      onResolve(enhancedView.deactivate(enhancedView, config.controller), () => {
        enhancedView.dispose();
        this.templates = undefined;
      });
    });

    return $template;
  }

```

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [December 10, 2025, 10:02pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/4 "2025-12-10T22:02:09Z")

</div>

> [@estaylorco](#):
>
> memory to leak because the inner enhanced content never disposes

I think as long as you are holding on to the enhancedView reference, its likely that some inner content wont be propey cleaned up. Aurelia should do better but shouldnt you also release that reference by setting enhancedView to null?

Thats just a guess, there could be more complication, like even the fact we are not cleaning up the event on template could also be a lead, because the callback holds a reference to the enhancedView, maybe we have to do a snapshot to check deeper.

> The big problem here is that the 3 components I pointed out above do not dispatch `dxremove` when the popup is hidden (by the close box, or by clicking outside). So I have no way to hook in.

Is this an issue with the widget, or something else? It doesnt sound like Aurelia related.

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [December 10, 2025, 10:15pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/5 "2025-12-10T22:15:25Z")

</div>

> I think as long as you are holding on to the enhancedView reference, its likely that some inner content wont be propey cleaned up

I am holding on to a reference, yes, with the expectation that `dxremove` will fire and I’ll be able to dispose of `enhancedView` correctly.

> Aurelia should do better but shouldnt you also release that reference by setting enhancedView to null?

That’s just it though: If `dxremove` doesn’t fire when closing the popup (popover, tooltip), when and by what means would I have an opportunity to set `enhancedView` to `null`?

> Is this an issue with the widget, or something else? It doesnt sound like Aurelia related.

I’m not sure “issue” is the right word here, but it’s definitely related to Aurelia. These same components (same versions) work as I write this in Aurelia 1.0 without a problem. It’s irrelevant that `dxremove` doesn’t fire under 1.0 because Aurelia cleans up the view.

Under 2.0, I’m the one who has to dispose (not to say that that isn’t a good thing in general), but it does change the contours of this use case.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [December 10, 2025, 10:42pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/6 "2025-12-10T22:42:20Z")

</div>

I was only speaking in general related to cleaning up the reference. From the look of the code, im not sure were to look. Maybe lets have a repro fitst? Please use stackblitz so its easier to run and test. [Aurelia app - conventions - Vite - StackBlitz](https://stackblitz.com/edit/au2-conventions-tvyh8c?file=src%2Fmy-app.html)

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [December 10, 2025, 10:45pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/7 "2025-12-10T22:45:33Z")

</div>

A couple of things. I’m using Webpack and javascript. Also, I don’t know if there’s a licensing issue with DevExpress/StackBlitz.

Let me check into it…

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [December 10, 2025, 11:37pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/8 "2025-12-10T23:37:46Z")

</div>

For webpack you can use this link [Aurelia app - conventions webpack - StackBlitz](https://stackblitz.com/edit/au2-conventions?file=src%2Fmy-app.html)

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [December 11, 2025, 12:46am UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/9 "2025-12-11T00:46:09Z")

</div>

The link you gave me involves typescript. I’m using webpack and _javascript_. It’s having trouble recognizing the ‘@’ character at `@customElement(…)`

Also, I would need basic routing since navigating away from the consuming component (page) it where the error is produced.

Do you have a webpack and babel StackBlitz with routing?

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [December 11, 2025, 5:01pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/10 "2025-12-11T17:01:45Z")

</div>

Hello @bigopon ,

Wow! I had never used StackBlitz before. Amazing!

**I have a repro for you at** [node.new Starter - StackBlitz](https://stackblitz.com/edit/stackblitz-starters-gbusmz8u) **.**

I figured out that I could start a **node.new** project and just run `npx makes aurelia` with the same setup I have. I had to move some files out into the root and adjust the webpack configuration slightly, but it was pretty straightforward.

To reproduce the error:

1. **Navigate to the About Page;**
2. **Click the Show Popover button;**
3. **Close the popover;**
4. **Navigate to the Welcome Page.**

The error you see will appear for the Popup, Popover, and Tooltip widgets. For those widgets, visibility is a fundamental part of the widget and managed by the widget itself. So using the visibility bindings of Aurelia doesn’t solve the problem.

I hope this helps.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [December 12, 2025, 11:05am UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/11 "2025-12-12T11:05:21Z")

</div>

this almost looks like a router bug, let’s check with @Sayan751 and @dwaynecharrington if they recall something first. Thanks @estaylorco

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [December 12, 2025, 4:57pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/12 "2025-12-12T16:57:22Z")

</div>

With that said, would it be helpful if I tried this with dynamic composition instead of routing, switch between two views—one containing the popover and the other not—to see if that produces the same error?

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [December 13, 2025, 1:20pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/13 "2025-12-13T13:20:53Z")

</div>

@estaylorco It seems that the enhanced view needs to be handled correctly. Here is a [working version](https://stackblitz.com/edit/stackblitz-starters-ku7yjvuv?file=tier1-app%2Fsrc%2FTsiDxAuTemplateBridgeService.js).

```diff
- const enhancedView = Aurelia.enhance({
+ onResolve(
+ Aurelia.enhance({
      container: config.container,
      host: $template,
      component: {
        data: renderData.model,
      },
- });
+ }),
+ (enhancedView) => {
      // Register a Dx remove event, dxremove, so we can apply Aurelia conventions to deactivating and disposing of an enhanced view
      // The widget will clean this up itself upon its disposal
      dxEventOn($template, 'dxremove', (e) => {
        console.log('dxremove dispatched...', __cloneDeep(e));
  
        if (!enhancedView) {
          return;
        }
  
        // This will trigger the tear-down lifecycle hooks of the enhanced view.
        onResolve(
          enhancedView.deactivate(enhancedView, config.controller),
          () => {
            enhancedView.dispose();
            this.templates = undefined;
          }
        );
      });
  
      return $template;
+ }
+ );

```

Explanation: the `Aurelia.enhance` can return a promise which needs to be handles properly. During deactivation of the about-view, the `dispose`of the enhanced view failed as `.dispose()` is not a method of promise (see below), which leads to the failure of the view deactivation and consequently the error observed.

![image](https://canada1.discourse-cdn.com/flex027/uploads/aurelia/original/2X/b/b5774fb0f577349211d538adbd8ed906a782f140.png)

Happy coding ✌

---

<div class="post-metadata">

**Author:** ![estaylorco](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/estaylorco/32/1887_2.png) [@estaylorco](https://discourse.aurelia.io/u/estaylorco)\
**Post date:** [December 13, 2025, 4:06pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/14 "2025-12-13T16:06:47Z")

</div>

@Sayan751 @bigopon

You have no idea what a relief that is to me! I worked hard on the Aurelia 1.0 solution a number of years ago, and it worked flawlessly. I was able to marry the best web framework in the world with the best component suite in the world! To see that again under Aurelia 2.0 is just wonderful.

Thanks so much to both of you!

What’s interesting, though, is that I travelled down the path of `async` on `enhance` early on, but because it didn’t work, I assumed that my scenario wasn’t actually async.

I initially had this:

```javascript
async createRenderer(rawTemplate, renderData, config) {
    const $template = rawTemplate.cloneNode(true);
    renderData.container.append($template);

    
    const enhancedView = await Aurelia.enhance({
        container: config.container,
        host: $template,
        component: {
          data: renderData.model,
        },
    });
...

```

but that didn’t work because Devextreme widgets can’t handle async renderers.

Then I tried this, and it didn’t work either:

```javascript
createRenderer(rawTemplate, renderData, config) {
    const $template = rawTemplate.cloneNode(true);
    renderData.container.append($template);

    Aurelia.enhance({
        container: config.container,
        host: $template,
        component: {
          data: renderData.model,
        },
    }).then((enhancedView) => {...};
...

```

The documentation doesn’t mention `onResolve`, but it looks like this is the magic dust we have to sprinkle on `enhance`.

Shouldn’t I have been able to refactor from `async-await` to a `then`? Or am I missing something here?

---

<div class="post-metadata">

**Author:** ![Sayan751](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/sayan751/32/1861_2.png) [@Sayan751](https://discourse.aurelia.io/u/Sayan751)\
**Post date:** [December 13, 2025, 7:16pm UTC](https://discourse.aurelia.io/t/conclusion-the-need-to-dispose-of-an-enhanced-view-interferes-with-some-third-party-integrations/6554/15 "2025-12-13T19:16:56Z")

</div>

You can also use async-await. There should not be any issue as well. The `onResolve` is just used widely in Aurelia internally to ensure immediate callback if the return value is not a promise, resulting in a synchronous operation, that’s all.

Fell free to use whatever matches your coding practices.
