Bootstrap modal in rails automatically opens when going to the previous link

264 views Asked by At

I've been following this video tutorial series in creating a Rails 7 app with Bootstrap v5.3 as CSS framework and Stimulus(Turbo) in javascript side.

Basically, I want to have a bootstrap modal to render form, create resources and view resources which I have already achieved.

The problem is that whenever I open a modal in /documents route and close it, then for some reason I have to visit another route, but when I go back to /documents route the modal automatically opens itself.

Here's my code following the video tutorial

application.html.erb

<main>
  <%= turbo_frame_tag 'remote_modal'  %>
</main>

sidebar.html.erb

<%= link_to new_document_path, class: "nav-link align-middle px-0", data: {controller: 'document-modal'} do %>
    <i class="fs-4 bi-plus-square-fill"></i> <span class="ms-1 d-none d-sm-inline">New log</span>
<% end %>

document_modal_controller.js

import { Controller } from '@hotwired/stimulus';

// Connects to data-controller="document-modal"
export default class extends Controller {
  connect() {}

  initialize() {
    this.element.setAttribute('data-action', 'click->document-modal#showModal');
  }

  showModal(event) {
    event.preventDefault();
    this.url = this.element.getAttribute('href');
    fetch(this.url, {
      headers: {
        Accept: 'text/vnd.turbo-stream.html',
      },
    })
      .then((response) => response.text())
      .then((html) => Turbo.renderStreamMessage(html));
  }
}

bs_modal_controller.js

import { Controller } from '@hotwired/stimulus';

// Connects to data-controller="bs-modal"
export default class extends Controller {
  connect() {
    this.modal = new bootstrap.Modal(this.element);
    this.modal.show();
  }

  disconnect() {
    this.modal.hide();
  }

  submitForm(event) {
    this.modal.hide();
  }

  hideBeforeRender(event) {
    if (this.isOpen()) {
      event.preventDefault();
      this.element.addEventListener('hidden.bs.modal', event.detail.resume);
      this.modal.hide();
      console.log(this.modal);
    }
  }

  isOpen() {
    return this.element.classList.contains('show');
  }
}

_form_modal.html.erb

<%= turbo_frame_tag :remote_modal, target: :_top do %>
    <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"
        data-controller="bs-modal">
    <div class="modal-dialog">
        <div class="modal-content">
        <div class="modal-header">
            <h1 class="modal-title fs-5" id="exampleModalLabel">Create new document</h1>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <%= render "form", document: document %>
        </div>
    </div>
    </div>
<% end %>

new.turbo_stream.erb

<%= turbo_stream.replace "remote_modal" do %>
  <%= render "form_modal", document: @document %>
<% end %>

_form.html.erb

 <%= f.submit class: "btn btn-primary", data: {action: "click->bs-modal#submitForm"} %>

I already tried clearing the browser's cache.

Any help will be much appreciated

1

There are 1 answers

0
ST. TOKYO CHANEL On

I actually solved this issue the day before yesterday. The reason why it automatically opens is because the connect method in your stimulus controller is set to automatically open the modal when it connects to the DOM, if you want to hide the modal after that you have to use this.modal.dispose() inside of the disconnect method currently you're using this.modal.hide() which isn't working for you because the modal that is created when the connect method connects to the DOM needs to disposed of completely, not hide temporarily. This will prevent the automatic pop up. The correct code is below:

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="bs-modal"
export default class extends Controller {
  connect() {
    this.modal = new bootstrap.Modal(this.element, {
      keyboard: false
    });
    this.modal.show();
  }

  disconnect() {
    this.modal.dispose();
  }

  submitEnd(event) {
    this.modal.hide();
  }
}