Skip to content

Ruby on Rails AJAX Modal Example

Andrew Kumanyaev edited this page Apr 28, 2016 · 8 revisions

This utilizes portions of this bootstrap-modal plugin, but also takes advantage of Ruby on Rails built in AJAX functionality. Im definitely not using the plugin to its full potential, so please feel free to edit this with more examples or suggestions.

In my example I am creating a Twitter-like private messaging system that is only accessible in a modal.

###application.html.erb or wherever put a link like this in your view to link to the modal. remote=true is where the rails ajax magic happens

<%= link_to "Messages", conversations_path, data: { toggle: "modal", target: "#ajax-modal" } %>

...

<%= render 'layouts/modal' %>

###_modal.html.erb added modal-body-content to have div i can replace html for. replacing html on modal-body would get rid of the ajax-loader

<div id="ajax-modal" class="modal hide fade" tabindex="-1">
  <div class='modal-header'>
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
    <h3 class="modal-title">Campustask</h3>
  </div>
  <div class='modal-body'>
    <div class="modal-body-content"></div>
    <div class="ajax-loader"></div>
  </div>
  <div class='modal-footer'>
    <button type="button" data-dismiss="modal" class="btn">Close</button>
  </div>
</div>

###_modal.html.haml Haml Alternative

#ajax-modal.modal.hide.fade{:tabindex => "-1"}
  .modal-header
    %button.close{"aria-hidden" => "true", "data-dismiss" => "modal", :type => "button"} &times;
    %h3.modal-title Campustask
  .modal-body
    .modal-body-content
    .ajax-loader
        loading....
  .modal-footer
    %button.btn{"data-dismiss" => "modal", :type => "button"} Close

###core.js.coffee i put these in core js file (written in coffee) since modal can be called + used on any page.

# called from a bootstrap dropdown, this closes the dropdown
$('a[data-toggle=modal]').on 'click', ->
  $('.dropdown').removeClass('open')
# this sets up the ajax loader, and it will stay until the method specific js removes it
$('a[data-target=#ajax-modal]').on 'click', (e)->
   e.preventDefault()
   e.stopPropagation()
   $('body').modalmanager('loading')
   $.rails.handleRemote( $(this) )
#removes whatever is in the modal body content div upon clicking close/outside modal
$(document).on 'click', '[data-dismiss=modal], .modal-scrollable', ->
  $('.modal-body-content').empty()
$(document).on 'click', '#ajax-modal', (e) ->
  e.stopPropagation()

###conversations_controller.rb similar for all methods. this will link to index.js.erb

def index
  sleep 1 #development only, simulates wait time
  respond_to do |format|
    format.html { redirect_to root_path } #for my controller, i wanted it to be JS only
    format.js
  end
end

###index.js.erb this will take care of the js + render an index partial with the relevant html

var title       =   '.modal-title',
    loader      =   '.ajax-loader',
    content     =   '.modal-body-content',
    dataRemote  =   'a[data-remote=true]',
    toolbar     =   'div.modal-footer',
    modal       =   '#ajax-modal';

//i set the title through a helper function
$(title).html('My Messages');
//hides the modal and shows the ajax content
$(loader).fadeToggle('fast', function() {
  $(loader).fadeOut('slow');
  $(content).html('<%= j render("index") %>');
  $(modal).modal();
});
//brings the loader back up + gets rid of the content when linking to another controller method etc
$(content).on('click', dataRemote, function(){
  $(content).fadeOut('slow', function() {
    $(content).empty();
    $(loader).fadeIn('slow');
  });
});

###_index.html.erb partial html that gets populated into the ajax modal. left in

<% mailbox.conversations.each do |conversation| %>
  conversation subject --- <%= link_to conversation.subject, conversation, remote: true %>
<% end %>
You can’t perform that action at this time.