Shawn Wilson
Shawn Wilson

Reputation: 1351

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.

Upvotes: 1

Views: 1147

Answers (1)

Arun Kumar Mohan
Arun Kumar Mohan

Reputation: 11915

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!

Upvotes: 3

Related Questions