2Do Consulting

Blog

Loading the Content for a Bootstrap Popover via AJAX

How to dynamically load content for a Twitter Bootstrap Popover.

A quick example follows below. If you want the full Ruby on Rails/Coffeescript example, skip this code and begin reading below.

Dynamically Loading Content for a Twitter Bootstrap Popover
1
2
3
4
5
6
7
8
9
10
11
12
13
$(document).ready(function() {
  $(".popover-trigger").click(function() {
    el = $(this);
    $.get("/path/to/resource", function(response) {
      el.unbind('click').popover({
        content: response,
        title: 'Dynamic response!',
        html: true,
        delay: {show: 500, hide: 100}
      }).popover('show');
    });
  });
});

Full Twitter Bootstrap/Ruby on Rails/Coffeescript Example

Let’s assume the following situation. We have a Ruby on Rails website that collects baseball player data. We have an index page that lists all the players and that links to individual pages for each player. Those individual pages have full season stats for the player. On the index page, we would like for the user to be able to quickly view a players recent stats without leaving the page. We don’t want to load all this data for every player whenever a user visits this page. Our solution is to use jQuery to make an asynchronous request when the user hovers over a “More Info” link that will appear next to each player’s name.

Our views and controller are moderately basic.

Lets say that we have an action in our controller that looks like this:

PlayersController
1
2
3
4
5
6
7
8
9
10
11
12
class PlayersController < ApplicationController
  before_filter :load_player

  def load_player
    @player = Player.find(params[:id])
  end

  def recent_stats
    @stats = @player.game_stats.last(5)
    render :layout => nil
  end
end

And that last_5_games responds with a view like:

last_5_games.js.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%= content_tag :h4, @player.name %>

<div style="display:none;">
  <div class="player-name">Recent Stats <%= link_to @player %></div>
</div>

<table>
  <tr>
    <th></th>
    <th>Value</th>
  </tr>

  <% @stats.each do |stat| %>
  <tr>
    <td><%= stat.name %></td>
    <td><%= stat.value %></td>
  </tr>
  <% end %>
</table>

And that our view looks like:

index.html.erb
1
2
3
4
5
6
7
8
<table>
<% @player.each do |player| %>
  <tr>
    <td><%= player.name %></td>
    <td><%= link_to 'More Info', '#', :class => 'more-info' %></td>
  </tr>
<% end %>
</table>

Then our coffeescript will look like this:

Binding our handlers
1
2
3
4
5
6
7
8
9
10
11
$(".more-info").each (index) ->
  $(this).bind 'hover', ->
    el = $(this)
    player_id = $(this).attr('data-player-id')
    callback = (response) ->
      el.unbind('hover').popover({
        content: response,
        title: $(response).find(".player-name"),
        delay: {show: 500, hide: 100}
      }).popover('show')
    $.get("/players/#{player_id}/recent_stats", '', callback, '')

Some things to note:

  • Our request returned an html snippet instead of JSON. If we wanted to use JSON we would have formatted the response before setting it to content in our callback.
  • Part of our response is a hidden div with the player name and a link to another page. This lets us set the title of the popover when we get a response.