Hi @sebastien ,
The best resource on this is probably the hotrails.dev article, How to make modals in a Rails application using Hotwire? . This approach utilizes the form to show/hide the modal as needed.
I follow essentially the same strategy, but I use event hooks (rather than Stimulus) to tie Hotwire to the CSS/JS framework. Here is how I do it in my applications if you are interested:
HTML:
- Add a turbo-frame element within the modal (e.g. “location-modal”)
- Add a matching turbo-frame element in the view to be rendered (e.g. new.html.erb)
- Add “data: { turbo_frame: “location-modal”" }” to your link (to trigger a turbo-frame response from outside of the turbo-frame within the hidden modal)
JS:
- Listen for the “turbo:frame-load” event, and use this to show the modal
- Listen for the “turbo:submit-end” event, and use this to hide the modal for a successful form submission
NOTE: the JS for this will vary depending on which CSS/JS framework you are using. Let me know if you are interested in seeing mine (Bootstrap based).
Custom Turbo Stream response:
To handle a successful form submission, you will likely want to add a custom turbo_stream response, both to clear the modal and to append the new/updated item to the page (since these locations are separate). Here is an example:
Controller (within the “create” action):
if @location.save
format.html { redirect_to @location, notice: "Location was successfully created." }
format.json { render :show, status: :created, location: @location }
format.turbo_stream
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @location.errors, status: :unprocessable_entity } end
View (app/views/locations/create.turbo_stream.erb)
<%= turbo_stream.append "locations", partial: "location", locals: { location: @location } %>
<%= turbo_stream.update "location-modal", "" %>
Additional JS components
For additional JS components (e.g. TinyMCE, ActiveText, or otherwise), you can tie the initialization of these components to the same “turbo:frame-load” event like so:
$(document).on('turbo:frame-load', "#location-modal", event => {
init_custom_fields();
});