Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Controllers don't reconnect after DOM mutations triggered by Morphdom #209

Closed
hopsoft opened this issue Nov 25, 2018 · 5 comments
Closed

Comments

@hopsoft
Copy link

hopsoft commented Nov 25, 2018

This may not be an issue with Stimulus but I wanted to bring it to your attention. I've noticed that Stimulus doesn't appear to recognize DOM mutations triggered by Morphdom.

I have a work around inspired by a conversation on a different issue.

import { Controller } from "stimulus"

export default class extends Controller {
  connect() {
    this.name = this.element.dataset.controller;
    document.addEventListener('cable-ready:after-morph', this.reconnect.bind(this));
  }

  reconnect() {
    setTimeout(() => this.element.setAttribute('data-controller', this.name), 1);
    this.element.setAttribute('data-controller', '');
  }
}

For more context see: https://github.com/hopsoft/cable_ready#stimulus-gotchas

Note that adding the event listener for each connect is problematic. My actual project guards against adding redundant listeners.

@javan
Copy link
Contributor

javan commented Nov 27, 2018

Are you mutating the DOM in such a way that the controller's element gets reconnected? Or, are you expecting another connect() after every document mutation (hence the global document listener)?

When this happens, such as after removing the controller’s element from the document and then re-attaching it, Stimulus will reuse the element’s previous controller instance, calling its connect() method multiple times.
https://stimulusjs.org/reference/lifecycle-callbacks#reconnection

@hopsoft
Copy link
Author

hopsoft commented Nov 27, 2018

My use case renders an HTML table (with a Stimulus controller) that has draggable rows. The drag/drop behavior is initialized in the table's connect. The user interacts with the table and it get re-rendered server side but Morphdom only applies the diff for DOM mutations. In this case it was only a few rows. That's why the table doesn't connect after the DOM update. Unfortunately drag/drop stops working for all rows when this happens.

I suspect that moving the row drag/drop event listener initialization to Stimulus actions may work. I'll try that and will report back shortly.

@hopsoft
Copy link
Author

hopsoft commented Nov 27, 2018

Verified that initializing drag/drop with Stimulus actions works and is the correct way to handle this scenario.

To be clear. I removed the drag/drop initialization from the table's connect method.

// app/javascript/controllers/table_controller.js
import { Controller } from 'stimulus';

export default class extends Controller {
  connect() {
    let rows = this.element.querySelectorAll('tr[draggable]');
    rows.forEach(tr => {
      tr.addEventListener('dragstart', this.dragStart);
      tr.addEventListener('dragend', this.dragEnd);
      tr.addEventListener('dragover', this.dragOver);
      tr.addEventListener('drop', this.drop);
    });
  }

  // ...
}

And I added Stimulus actions to each individual row.

<table data-controller="table">
  <tr draggable 
    data-action="dragstart->table#dragStart dragend->table#dragEnd dragover->table#dragOver drop->table#drop">
    ...
  </tr>
</table>

Thanks for being patient, letting me talk this out, and find the right solution.

@hopsoft hopsoft closed this as completed Nov 27, 2018
@javan
Copy link
Contributor

javan commented Nov 27, 2018

And I added Stimulus actions to each individual row.

Nice! That's the Stimulus Way™ ;)

BTW, your action descriptors are missing event names:

 <tr draggable data-action="dragstart->table#dragStart dragend->table#dragEnd …">

@hopsoft
Copy link
Author

hopsoft commented Nov 27, 2018

Oh whoops. I updated my example for posterity ;-)

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

No branches or pull requests

2 participants