Using Modals with Turbo-Frames
The Goal
To create a modal form and make it appear in your current view. The following is extracted from live production code.
How do we do it?
We’ll need:
- Stimulus JS
- Turbo Rails
- (And in my case: Bootstrap + JQuery)
## Some view
<%= turbo_frame_tag "new_group" do %>
<%= link_to "New group", new_group_path %>
<% end %>
Explanation of the above code snippet: When we are on a particular page, we want to create a new group without navigating away from that page. Why? In order to make it a better user experience.
The user hits the new group link and is presented with the following modal. I’m using bootstrap. I have elided most of the complex bits so you can copy/paste according to your own needs:
# groups/new.html.erb
<div class="container">
<%= turbo_frame_tag "new_group" do %> <!-- Note the turbo frame -->
<!-- note the stimulus controller -->
<div data-controller="modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"> Create Group</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<------- Im reusing this partial hence the locals passed in ------->
<%= render "groups/form", locals: {url: group_path(@project), method: :post} %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<------- We add this, so after the modal is cancelled etc. we can still have a button to open up the modal again ------->
<%= link_to "New group", new_group_path() %>
<% end %>
</div>
We need a controller to activate the modal the second it appears in the dom. And we want to hide it the second it disappears.
/// modal_controller.js
import { Controller } from "stimulus";
export default class extends Controller {
connect(){
$(this.element).modal();
}
disconnect() {
$(this.element).modal('hide');
}
}
# groups/show.html.erb
<%= turbo_frame_tag "new_group" do %>
<!-- simply display what you want to display when a new group is created -->
<% end %>
# finally redirect to the show action upon successful creation of the group record
## groups_controller
def create
if @group.save
redirect_to @group
end
end
I’m by no means an expert on the intricacies of turbo-rails, so I might have missed something - if so please let me know.
I may post a giphy to show how it works, if I get the opportunity.
I hope this helps!