Gerry Gerry - 12 days ago 4
Ajax Question

Rails + Bootsrtap + AJAX: modal with form stops showing after submit

I have an index view for a model (all records shown) and i use bootstrap and ajax to make updates within the index view. To accomplish this i added a link at the end of each row that, after clicking it, displays a modal with a form with the record's attributes. I submit the form and, using ajax, i update the db and then update the view (only the row that was changed).

It works fine for the first time, but if i try to edit again the same row the modal stops displaying, clicking does nothing, not even an error message. It still works, though, with the other rows.

If i remove the rendering from the update.js.erb (see code below) it works too, every time, but then i need to refresh the whole page (after every change) to show update changes.

The code remains exactly the same (or so it seems) but i need to refresh the page in order to make it work again on the updated row(s).

Here's my code:

controler (removed not relevant code)

before_action :set_status, only: [:edit, :update]

def edit
end

def update
@status.update(status_params)
respond_to :js
end

private

def set_status
@status = Status.find(params[:id])
end


index view

<div class="container contentaftermenu">
<div class="row">
<table class="table">
<thead class="table-head">
<tr>
<th class="centered">Sequence</th>
<th>Title</th>
<th>Description</th>
<th class="centered">Edit</th>
</tr>
</thead>
<tbody>
<% @statuses.each do |status| %>
<tr class="record-tr" id="status-<%= status.id %>">
<%= render partial: "display", locals: { status: status } %>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
<div id="status-modal" tabindex="-1" role="dialog" class="modal fade"></div>

<script type="text/javascript">
$(document).ready(function () {

$('img.bottom').click(function() {
$('#status-modal').modal("show");
});
});
</script>


display partial

<td class="centered"><%= status.sequence %></td>
<td id="title-<%= status.id %>"><%= status.title %></td>
<td id="desc-<%= status.id %>"><%= status.description %></td>
<td id="act-<%= status.id %>" class="centered">
<%= link_to edit_admin_status_path(status), remote: true do %>
<img id="sid-<%= status.id %>" class="bottom" src="../../images/admin/edit.png">
<% end %>
</td>


edit js

$("#status-modal").html("<%= j(render 'form') %>");


form partial

<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3 class="modal-title">Edit status</h3>
</div>
<%= form_for @status, url: admin_status_path(@status), remote: true do |f| %>
<div class="modal-body form-group form-admin">
<ul class="errors alert-danger"></ul>

<div class="form-group">
<%= f.label :title, class:"control-label" %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :description, class: "control-label" %>
<%= f.text_area :description, class: "form-control" %>
</div>

<%= f.submit class: "btn btn-primary" %>
<%= link_to "Cancel", "#", class: "btn", data: { dismiss: "modal" } %>
</div>
<% end %>
</div>
</div>


update js

$("ul.errors").html("");
$("ul.errors").removeClass("alert");

<% if @status.errors.any? %>
$("ul.errors").addClass("alert");

<% @status.errors.full_messages.each do |message| %>
$("ul.errors").append($("<li />").html("<%= message.html_safe %>"));
<% end %>
<% else %>
$("#status-<%= @status.id %>").html("<%= j(render partial: 'display', locals: { status: @status }) %>");
$("#status-modal").modal("hide");
<% end %>


Thank you for your help!

Answer

I think the problem is that you are replacing all the html inside the modal with your edit.js which means that the JS modal object no longer exists, so that your on click function to show the modal can no longer find the modal object.

Could you try replacing just the part of modal that has the form, and that should solve your issue.

I.e. make a partial for just this bit (I gave it an id of "inner_form"):

<%= form_for @status, url: admin_status_path(@status), remote: true, id:"inner_form" do |f|   %>
  <div class="modal-body form-group form-admin">
    <ul class="errors alert-danger"></ul>

    <div class="form-group">
      <%= f.label :title, class:"control-label" %>
      <%= f.text_field :title, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= f.label :description, class: "control-label" %>
      <%= f.text_area :description, class: "form-control" %>
    </div>

    <%= f.submit class: "btn btn-primary" %>
    <%= link_to "Cancel", "#", class: "btn", data: { dismiss: "modal" } %>
  </div>
<% end %>

then just replace that in your edit.js:

$("#inner_form").html("<%= j(render 'inner_form') %>");