Dynamically load content into Bootstrap Modal (using Turbo/Stimulus)


I tried asking this on stackoverflow but no answers

I would like to dynamically load content into a Bootstrap 5 Modal dialog using Turbo Frames.
I’ve previously done this with Bootstrap 4/Rails 6 by opening the modal dialog the standard bootstrap way (using data-modal-toggle attributes, and in Bootstrap 4 this then still allowed the A HREF location to be fetched and could be placed into Modal body using UJS. In Bootrap 5 the fetch does not happen (nothing sent to server) so I cannot use this same approach in my new app (but with Turbo rather than UJS).

I’ve tried a few strategies but they all seem clunky. The most obvious solution seems to be to replace what I’ve done before with UJS by having the Stimulus Controller catch the “click” message and trigger a fetch to the server to grab the Turbo Frame content and insert it into the Modal.

Is there a Turbo-native/Javascript method for performing this (i.e.: issue a GET, and automagically insert the content into the Turbo Frame)?


Okay some progress (always happens when you post a question):

In my Stimulus controller:

    fetchModalContent() {
        this.href = this.element.getAttribute("href")
        Turbo.visit(this.href, { action: "replace" })

Fetches the content but does not seem to target the relevant frame.

My link:

                        <%= link_to "+", url_for([list, @item.itemable, action: :new]),
                            data: { 
                                turbo_frame: "remote_modal_content", 
                                bs_toggle: "modal", 
                                bs_target: "#remote_modal",
                                controller: "remote-modal",
                                action: "click->remote-modal#fetchModalContent" },
                            role: "button", class: "btn btn-outline-primary btn-sm me-1 d-inline-block" %>

The frame into which it it meant to be inserting the content:

<%= turbo_frame_tag "remote_modal_frame" do %>

<div class="modal fade" id="remote_modal"
    tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <%= turbo_frame_tag "remote_modal_content" %>

<% end %>

The partial which is being returned:

<%= turbo_frame_tag "remote_modal_content" do %>

    <div class="modal-content">
        <div class="modal-header">
            <h1 class="modal-title fs-5"><%= title %></h1>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        <div class="modal-body" id="remote_modal_body">
            <%= yield %>
        <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<% end %>

Okay I’ve got it… no thanks to you lot :wink:

    fetchModalContent() {
        let href = this.element.getAttribute("href")

        let frame_id = "turbo-frame#" + this.element.getAttribute("data-turbo-frame")
        let frame = document.querySelector(frame_id)
        frame.src = href