Today I worked out an example of using the Bootstrap modal component in a Turbo Frame.
This link triggers the response with the Turbo Frame containing the Boostrap modal. It is not inside a Turbo Frame, so the data-turbo-frame
attribute is used to specify which Turbo Frame is the target:
<%= link_to "Open Modal", edit_article_path(@article), data: { turbo_frame: "modal" } %>
This is the target Turbo Frame to be replaced:
<turbo-frame id="modal" target="_top">
</turbo-frame>
This is the ERB with the replacement Turbo Frame which has the Bootstrap modal:
<turbo-frame id="modal">
<div class="modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Editing article "<%= @article.title %>"</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<%= render "form", url: article_path(@article) %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</turbo-frame>
The problem with this is the Bootstrap modal will not show itself just from being inserted in the DOM as a Turbo Frame.
To accomplish that, add an event listener in application.js
that listens to the "turbo:frame-load"
event and shows the modal:
import { Modal } from "bootstrap";
document.addEventListener("turbo:frame-load", (event) => {
if (event.target.id === "modal") {
const modalElement = document.querySelector("#modal .modal");
if (modalElement) {
const modalInstance = new Modal(modalElement);
modalInstance.show();
}
}
});
With this, the modal will show itself when it’s inserted in the DOM as a Turbo Frame.