What is best way to fire event on controller connect()?

Hey @floydj!

Welcome! First question - Do you intend to have multiple checkboxes and corresponding controlled targets in one controller? That’s not what’s indicated in your sample HTML, but the JS does imply it. In which case, you have a bug - you’re dispatching an event for each target, but then each event triggers controlIt which then loops over all controlled targets, but only comparing them all, each time, against a single check box.

This would leave every controlled target in the enabled state of only the last checkbox. Doh! Moreover, if you have 4 checkboxes/controlled targets, controlIt would be called 16 times.

There are threads like this that discuss some of the merits and solutions for using one controller for all boxes/targets or one controller for each pair. One controller for each pair for a simple use case such seems much more straight forward, and gets rid of the situation described above, so I’ll describe what that solution would look like.

// check_controller.js
export default class extends Controller {
  static targets = [ 'checkBox', 'controlled' ];

  connect() {
    this.update()
  }

  update() {
    this.controlledTarget.disabled == !this.checkBoxTarget.checked
  }
}

And the HTML:

<div data-controller="check">
  <input data-action="check#update" data-target="check.checkBox" name="custom_paint" type="checkbox" />
  <input name="custom_paint_color" type="text" data-target="check.controlled" />
</div>

Pretty straightforward!

Now, one last thing I would strongly suggest - if you’re rendering the HTML dynamically (e.g. via Rails), set the state in the HTML itself rather than relying on JS. This would allow you remove the connect() call altogether, but more importantly it removes N number of repaints from your page. If you have a list of 20 of these, they each may be repainted as soon as the controller connects. It may seem minor, but it just adds overhead every time the page is loaded.

So then you’d have HTML that looks like:

<!-- Checked + enabled -->
<div data-controller="check">
  <input data-action="check#controlIt" data-target="check.checkBox" name="custom_paint" type="checkbox" checked />
  <input name="custom_paint_color" type="text" data-target="check.controlled" />
</div>

<!-- Not checked and disabled -->
<div data-controller="check">
  <input data-action="check#controlIt" data-target="check.checkBox" name="custom_paint" type="checkbox" />
  <input name="custom_paint_color" type="text" data-target="check.controlled" disabled />
</div>

Hope this helps!

1 Like