Shawn Wilson Shawn Wilson - 3 months ago 9
Ajax Question

Rails 5 Bootstrap 3 Modal / Ajax not working

I am building out an app in Rails 5 and using Bootstrap 3 for the framework.

I have created a custom user controller ect to allow admins to create / edit and destroy users. I am setting up modals for the create user form, the modal its self works, however I want it to automatically place and render the table row.

So far when I create a user the modal hangs, it creates the user but dose not close the modal window and if I reopen the modal from the button it still holds the previous users email and details.

I will say that I have placed format.js in the Create, Update and Destroy Controller Actions under format.


My Modal and Its Button


<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#userCreate">
Add New User
</button>

<!-- Modal -->
<%= form_for(@user, remote: true) do |f| %>
<div class="modal fade bs-example-modal-lg" id="userCreate" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel"><i class="fa fa-user-plus" aria-hidden="true"></i> User Creation</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-xs-12">
<div class="field">
<%= f.label :email, "Email Address - Password Will Be Sent To This Address" %><br />
<%= f.email_field :email, autofocus: true, :class => 'form-control email' %>
</div>
</div>
</div>

<div class="row">
<div class="col-xs-12 col-sm-6">
<div class="field">
<%= f.label :f_name, "First Name" %>
<%= f.text_field :f_name, :class => 'form-control f_name' %>
</div>
</div>
<div class="">

</div>
<div class="col-xs-12 col-sm-6">
<div class="field">
<%= f.label :l_name, "Last Name" %>
<%= f.text_field :l_name, :class => 'form-control l_name' %>
</div>
</div>
</div>
<div class="row">
<div class="">

</div>
<div class="col-xs-12">
<div class="field">
<%= f.label :primary_tel, "Primary Telephone" %>
<%= f.text_field :primary_tel, :class => 'form-control primary_tel' %>
</div>
</div>
<div class="">

</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<%= f.submit "Create User", :class => 'btn btn-primary' %>
</div>
</div>
</div>
</div>
<% end %>



Index Page where the _user_row.html.erb Partial is to be rendered


<table>
<thead>
<tr>
<th>User ident</th>
<th>F name</th>
<th>L name</th>
<th>Primary tel</th>
<th>Role</th>
<th colspan="3"></th>
</tr>
</thead>

<tbody>
<% @users.each do |user| %>
<div class="row" id="user_table_row">
<%= render partial: 'user_row', locals: {user: user} %>
</div>
<% end %>
</tbody>
</table>


Now this partial is displaying, but only after I manually reload the page


And finally the create.js.erb file (located in views/users)


$('#userCreate').modal('hide'); <-- close the Modal On Submit
$(".email").val(''); <-- Reset Email Field
$(".f_name").val(''); <-- Reset F_name Field
$(".l_name").val(''); <-- Reset L_name Field
$(".primary_tel").val(''); <-- Reset Telephone Field

$('#user_table_row').prepend('<%= j render @user %>'); <-- Render User
$('#user_row_<%= user.user_ident %>').hide().fadeIn(1000); <-- Display Row


I am newish to jquery but im stumped here.. Any help would be greatly appreciated! Please let me know if you need to see anything else. Thanks.

also the <-- is not present in my app code i placed these there so you know what i am trying to do.

Answer

I assume that your user_row partial looks something like this.

<tr id="<%= "user_row_#{user.id}" %>">
  <td><%=user.email%></td>
  <td><%=user.f_name %></td>
  <td><%=user.l_name %></td>
  <td><%=user.primary_tel %></td>
</tr>

There are a couple of issues with your code in create.js.erb. You should actually render the partial user_row not just @user.

If you look at the server logs, you can find that it looks for a partial users/_user if you have render @user. So, replace that with

$('#user_table_row').prepend('<%= j render partial: 'user_row', locals: {user: @user} %>');

And in the following line of code,

$('#user_row_<%= user.user_ident %>').hide().fadeIn(1000);

user is nil. From the create action, you have access to an instance variable @user, not user. And I am not sure what user_ident is. Replace that with

$('#user_row_<%= @user.id %>').hide().fadeIn(1000);

Now, your AJAX form submission should work. But the new row will be rendered outside the table. To understand it better have a look at this.

So, where is the problem? In your view, you have the following block of code.

<% @users.each do |user| %>
  <div class="row" id="user_table_row">
    <%= render partial: 'user_row', locals: {user: user} %>
  </div>
<% end %>

For every user, you're wrapping the row(from partial) inside a div with class row and id user_table_row. Don't you see something wrong?

IDs should be unique throughout the page but you're creating multiple divs with the same id. Whenever a new user record is created, you've to prepend it to the table body. So, it would make sense to add the id to tbody rather than a wrapper div. So, modify your view as

<tbody id="table_body">
<% @users.each do |user| %>
    <%= render partial: 'user_row', locals: {user: user} %>
<% end %>

Now, you can prepend the new row to #table_body using Jquery like

$('#table_body').prepend('<%= j render partial: 'user_row', locals: {user: @user} %>');

Thats it!

Hope this helps!