Last Updated: February 25, 2016
·
1.94K
· manudwarf

PushState navigation and title issues

Hi guys,

For http://bustram-angers.fr/ (written in RoR) I had a couple of issues to deal with Backbone and pushState.

Parenthesis, if you don't know about ghost views, check this post : http://coenraets.org/blog/2012/01/backbone-js-lessons-learned-and-improved-sample-app/

So, here is the issue : if you hit http://bustram-angers.fr/ and then click on the "Récents" tab, the content will be the same as if you did directly type the URL in your browser, but the title didn't change.

I found out a little trick to fix that. Basically, I have a different template for "regular" and "pushState" requests.

When I load a new page, it's not just the HTML content but a JSON object passing the content, the title and the description.

app/controllers/application_controller.rb

layout :get_layout

protected

def get_layout
  request.xhr? ? params[:includeContext] == "true" ? "ajax" : nil : "application"
end

I have to explicitly pass "includeContext=true" when I load a new page to avoid interfering with other AJAX requests.

app/helpers/application_helper.rb

def title(page_title)
  content_for :title, page_title.to_s
end

def description(description)
  content_for :description, description.to_s
end

app/views/layouts/ajax.html.erb

{
  "content": "<%= yield.gsub("\n", " ").gsub("\"", "\\\"").html_safe %>",
  "description": "<%= yield :description %>",
  "title": "<%= content_for?(:title) ? yield(:title) + " - " : "" %>Horaires Bus-Tram Angers"
}

Don't forget to escape double quotes and remove line returns. Otherwise, your JSON will be incorrect.

On the JS side, here is my loading function :

$.get(url, {includeContext: true}, function(data) {
  var jsonData = JSON.parse(data);

  _this.$el.html(jsonData.content);
  document.title = jsonData.title;
  $('meta[name=description]').attr("content", jsonData.description);
});

And that's it ! Here is what a view looks like :

<% title @stop.name %>
<% description "Prochains passages bus tram pour l'arrêt #{@stop.name} (#{@stop.city_name})." %>

<article id="showStop" class="stop">
[...]

2 Responses
Add your response

Instead of having 2 separate templates can you just embed those metadata into the rendered HTML itself?

over 1 year ago ·

I could, but then I would have to go through the DOM, take the content element, the title and the description (which is what does turbolinks if I'm correct).
It just doesn't feel right to me.

over 1 year ago ·