Skip to content

disconnect() not called if outlet is accessed in connect() #763

Description

@sebastianludwig

I noticed that accessing an outlet in connect() causes the reference count of that controller to be 2 instead of 1 after start has finished. That means all actions which under normal circumstances cause the controller to be disconnected (like removing the data-controller attribute) don't cause the disconnect anymore.

The following code snippet illustrates the problem

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <script type="module">
    import { Application, Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js"
    window.Stimulus = Application.start()

    Stimulus.register("child", class extends Controller {
      connect() {
        console.log("Child connected")
      }
      disconnect() {
        console.log("Child disconnected")
        alert("works as expected")
      }
    })

    Stimulus.register("parent", class extends Controller {
      static outlets = [ "child" ]
  
      connect() {
        console.log("Parent connected")
        console.log(this.childOutlet) // <- works without this line 💥
      }
      disconnect() {
        console.log("Parent disconnected")
      }
      
      listChildren() {
        console.log(this.childOutlet)
      }
    });

    document.getElementById("remove").addEventListener("click", function() {
      console.log("Removing data-controller attribute");
      document.getElementById("child").setAttribute("data-controller", "");
    });
  </script>
</head>
<body>
  <div id="parent" data-controller="parent" data-parent-child-outlet="#child">
    <button data-action="click->parent#listChildren">List children</button>
  </div>
  <div id="child" data-controller="child"></div>
  <button id="remove">Remove data-controller=child attribute</button>
</body>
</html>

Setting a breakpoint in ScopeObserver.elementMatchedValue() and reloading the page you can see that it is hit twice for child. Clicking the remove button does not trigger disconnect() to be called. Everything works as expected with the marked line commented out.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions