Bootstrap Modal in Rails Keeps displaying the firs

2019-02-20 22:20发布

问题:

When I click on the View in Modal, it keeps on displaying only the first record. Even if I click on the second record it still displays the first one. Below is how I implemented the link_to toggle to modal box called myModal.

<%= link_to 'View in Modal', "#", data: {toggle: "modal", target: "#myModal"} %>
      <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
            <h4 class="modal-title" id="myModalLabel">Test</h4>
          </div>
          <div class="modal-body">
            <span class="note"><%= raw(usernote.note) %></span>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            <button type="button" class="btn btn-primary">Save changes</button>
          </div>
        </div>
      </div>
  </div>

回答1:

3 options here:

  1. generate one modal for each record - the worst thing you can do
  2. use data attributes to update content of the modal
  3. use ajax action where you'll update the content of the modal and open the modal with $('#myModal').modal('show') http://getbootstrap.com/javascript/#modals-usage

1. generate one modal for each record

<% @usernotes.each do |usernote| %>
  <%= link_to 'View in Modal', "#", data: {toggle: "modal", target: "#myModal_<%= usernote.id %>"} %>
  <div class="modal fade" id="myModal_<%= usernote.id %>" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    ....
    <span class="note"><%= raw(usernote.note) %></span>
    ....
  </div>
<% end %>

2. use data attributes to update content of the modal

<% @usernotes.each do |usernote| %>
  <%= link_to 'View in Modal', "#", data: {usernote: usernote.note}, class: 'user_note_modal' %>
<% end %>

 $('.user_note_modal').on('click', function() {
    $('#myModal span.note').html($(this).data('usernote'));
    $('#myModal').modal('show');
  });

p.s. why use .modal('show')? just so you make sure to update the content of the modal first then display it.


3. use ajax action - assuming your resource name is UserNote and you have user_notes_controller with show action:

<% @usernotes.each do |usernote| %>
  <%= link_to 'View in Modal', usernote_path(usernote), data: {toggle: "modal", target: "#myModal"}, remote: true %>
<% end %>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-body">
    <span class="note"></span>
  </div>
</div>

clicking on one link will trigger an ajax event that will expect a show.js.erb template, where you'll update the content of the modal and then display it:

app/views/user_notes/show.js.erb

$('.modal-body span.note').html('<%= j(render @usernote.note) %>');
$('#myModal_').modal('show');


回答2:

The problem

I supposed you've done something like:

<% @usernotes.each do |usernote| %>
 <%= link_to ... %>
 // code of modal associated to the usernote
<% end %>

The problem is that you used the same html ID for all the modals (#myModal).Besides the fact ID duplication is not W3C conform, this is the cause of the issue.

When you will click on one of the links, it will open the first modal with the #myModal ID (which is the modal of the first record).

So, how to patch the issue?

Easy way: one modal per usernote

One way, the easy way, is to use different IDs for all the modals. For example:

<%= link_to ... data: {toggle: "modal", target: "#modalForUserNote#{ usernote.id }"} %>
  <div id="modalForUserNote<%= usernote.id %>" ...>
  // ....

But this way is not the best one: you just create one modal per usernote... If you have 1000 usernotes, you will generate 1000 modals in your html... This is obviously pretty bad...

An other way: javascript callback

An other way to do it will be to create only one modal and to edit its content with some Javascript code.

An example of code can be:

html code

  // the modal code

  <% @usernotes.each do |usernote| %>
    <% link_to ..., data: {toggle: "modal", target: "#modal"}, 'data-usernoteid' => ..., 'data-usernotedata' => ... %>
  <% end %>

javacript code (using jQuery)

  $('.modalLink').on('click', function() {
    $('#modal #idOfTheUserNote').html($(this).data('usernoteid'));
    // ...
  });

You can note the usage of data attributes. Data attributes can be replaced by an AJAX request to your Rails application which will returns JSON data.

An other way: AJAX request

The last way to do it is to request your Rails application with an Ajax call. Your application will render an Javascript view (the code will be sent to your browser and evaluated).

This can be simply done by using the remote: true option in your link_to (rails will handle the ajax request by itself.

The following code can do the trick:

html code

  // the modal code

  <% @usernotes.each do |usernote| %>
    <% link_to 'text', some_action(usernote), data: {toggle: "modal", target: "#modal"}, remote: true %>
  <% end %>

controller code

   def some_action
     @usernote = Usernote.find_by_id(param[:id])
   end

view to render: for example usernote/some_action.js.erb

   $("#modal #modalIdOfTheUsernote").html("<%= @usernoed.id %>");

What is the best way to do it?

Obviously not the first one.

Choosing between the two others just depends on what you want to do:

  • For real time updates, AJAX request may be better. But you can get some latency because you need to wait the server response.

  • Otherwise, data attributes are good enough.