Use Stimulus and Turbo
If you are using both Stimulus and Turbo from Hotwired, here’s a Stimulus controller I recommend setting up on your popover layouts to improve your developer experience and easily controller the popovers.
This uses the Stimulus dispatch API and Turbo events.
<%# app/popovers/layouts/popover.html.erb %>
<div class="popover-layout" data-controller="popover">
<%= yield %>
</div>
// app/javascript/controllers/popover_controller.js
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="popover"
export default class extends Controller {
connect() {
this.dispatch('open', {
target: this.coupdoeilElement, detail: { popover: this.popoverElement, controller: this }
})
}
disconnect() {
this.dispatch('close', { target: this.coupdoeilElement })
}
closeOnSubmitSuccess(event) {
if (event.detail.success) {
this.close()
} else {
// handle error if needed
}
}
close() {
this.popoverElement.close()
}
get coupdoeilElement() {
return this.popoverElement.coupdoeilElement
}
get popoverElement() {
return this.element.parentElement
}
}
The full file can also be found in the repository: app/javascript/controllers/popover_controller.js
.
This way, you get events when the popover opens and closes.
document.addEventListener("popover:open", (event) => {
console.log(event.target) // the <coup-doeil> element
console.log(event.detail.popover) // the popover element (the wrapper, abose the layout)
console.log(event.detail.controller) // the stimulus controller
})
document.addEventListener("popover:close", (event) => {
console.log(event.target) // the <coup-doeil> element
})
You can also trigger closing when a form is submitted but only when it’s successful, using Turbo submit-end event:
<%# app/popovers/contact_popover/subscribe.html.erb %>
<div>
<%= form_for [:subscribe, @contact],
html: { data: { action: "turbo:submit-end->popover#closeOnSubmitSuccess" } } do |f| %>
<%# … %>
<%= f.submit class: "btn btn-primary" %>
<% end %>
</div>