Skip to content

Using a layout in site navigation

Ronald Chan edited this page Mar 13, 2012 · 6 revisions

This guide assumes that you have followed the guide, Adding AJAX to site navigation.

If you have done that, you may have noticed two small details.

  • The title does not change, even if the title in the non-AJAX version changes. Of course, this will not affect you if the title is the same throughout the whole site.
  • Flashes may not work as well as you would like. This might depend on how you use the flash notice or alerts. If they are included in specific view templates, only for specific actions, then it will not affect you. If flash notices are only displayed when using a non-AJAX link, it will not affect you.

This guide will help you solve both potential problems elegantly.

Title

To solve this, we will first assume your title is given by the following generic code in your application layout (where exactly you obtain the title from should not affect this guide):

<title><%= yield :title %></title>

Similarly, if you followed the guide for adding AJAX to site navigation, your application layout should also contain:

<%= ajax_section :id => "global", :loadzone => true do %>
  <%= yield %>
<% end %>

Before presenting the solution, you should briefly know how AJAX Pagination deals with responses to AJAX requests.

To make it easy to use this gem, it will accept full page responses, where only part of the page contains the content required. This is detected by checking to see if a <div> tag exists, with the same id as the page section being replaced, in which case only the new content inside that <div> tag is moved to the page section. The full page content might be:

<html><head></head>
  <body><div>A bunch of useless content</div>
    <div id="global_paginated_section">
      Content that is required!
    </div>
  <div>More useless content</div></body>
</html>

However, because this means sending more data than is necessary, all usage guides show how setup so that only the content required is sent. This is of course detected by the absence of <div> tag mentioned above. In this case, only the content is sent, and it might look like:

      Content that is required!

There is however yet another format which is accepted.

<html><head><title>My new title</title></head>
  <body>
      Content that is required!
  </body>
</html>

Notice that only the content required is sent - except for <html>, <head>, <title> and <body> tags. In this case, AJAX Pagination notices that a title is present. When a title is present, AJAX Pagination will start using the new title. Actually, the <html>, <head> and <body> tags are ignored by the browser when they are inserted into the page.

But how do we send this type of response?

It is actually very simple. We create a new layout, let's call it views/layouts/ajax.html.erb, with the following layout:

<html>
<head>
  <title><%= yield :title %></title>
</head>
<body>
  <%= yield %>
</body>
</html>

Then we simply tell it to use this layout. So in the application controller, we simply change the call to the ajax_respond class method to the following:

class ApplicationController < ActionController::Base
  ajax_respond :section_id => "global", :render => { :layout => "ajax" }

  ...
end

As you can see, we simply need to make two simple changes, and we've fixed the title.

Flash notices

Now what do we need to do to get the flash notices to show up? It is actually very simple, if we organise the layouts in the right way. If a flash exists, we want it to show up whether a full page is being loaded, or an AJAX page is being loaded. Therefore, we should create a new layout file, views/layout/flash.html.erb:

<% if flash[:notice] %>
  <p id="notice"><%= flash[:notice] %></p>
<% end %>
<% if flash[:alert] %>
  <p id="alert"><%= flash[:alert] %></p>
<% end %>
<%= yield %>

Here, we just have 7 lines displaying whatever flash notices might appear, and finally, yield for all the other content.

Then, we alter the views/layouts/application.html.erb file, and instead of the yield, we call the new layout as shown below:

<%= ajax_section :id => "global", :loadzone => true do %>
  <%= render :template => "layouts/flash" %>
<% end %>

We do the same thing with the views/layouts/ajax.html.erb file that we created (to fix the title):

<html>
<head>
  <title><%= yield :title %></title>
</head>
<body>
  <%= render :template => "layouts/flash" %>
</body>
</html>

Now, whether a full page is requested, or an AJAX page is requested, if any notices exist, they will display just above the page content.