Reputation: 1684
I have 4 tab sections in an Event page view. I have it working where ALL the content for each tab is fetched and rendered when an Event page is requested. This doesn't seem like a good solution for scalability...
How do I fetch the content for each tab using AJAX when a tab is clicked on?
(First time doing it... looks simple in theory but failing to get it working)
I tried adding remote: true
to the tab links but that doesn't play well with the in-page references - it makes the same get request Events#Show
for all the tabs which makes it difficult to determine which tab content is requested. If I change the tab href's to their respective controller links, then it breaks the bootstrap tab switching. I'm loosing either way.
Each tab's content is broken into separate controllers so individual content can be fetched.
For Tab#2, I need to fetch the content for which ever nav-pill
is active. And if I'm on Tab#2, I want to switch its content from Overview to Details and back using the nav-pills
button links.
Using Rails 4 w/ bootstrap 3, haml, coffeescript.
events/show.html.haml
/ Nav tabs
%ul.nav.nav-tabs.color
%li.active
=link_to "Tab1", "#tab1", html_options = { "data-toggle" => "tab" }
%li
=link_to "Tab2", "#tab2", html_options = { "data-toggle" => "tab" }
%li
=link_to "Tab3", "#tab3", html_options = { "data-toggle" => "tab" }
%li
=link_to "Tab4", "#tab4", html_options = { "data-toggle" => "tab" }
/ Tab panes
.tab-content
.tab-pane.active#tab1
%p Fetch content
.tab-pane.active#tab2
%ul.nav.nav-pills
%li.active= link_to 'Overview', "#overview", html_options = { "data-toggle" => "tab"}
%li= link_to 'Details', "#details", html_options = { "data-toggle" => "tab"}
.tab-content
.tab-pane.active#overview
%p Fetch overview
.tab-pane.active#details
%p Fetch details
.tab-pane.active#tab3
%p Fetch content
.tab-pane.active#tab4
%p Fetch content
controllers/events_controller.rb
def show
# currently have several database queries to get data for each tab :(
respond_to do |format|
format.html
format.js
end
end
views/events/show.js.erb (This was for the remote:true
case but should be in the respective controller view for each tab)
$('div#tab2').append("<%= escape_javascript(render(partial: 'overview', locals: {names: @names, genders: @genders, ages: @ages})) %>")
Upvotes: 3
Views: 5613
Reputation: 20600
Building off of swazza85's answer, if you want it to load only once (the first time the tab is clicked):
$('a[data-toggle="tab"]').on('show.bs.tab', function (e) {
var currTabTarget = $(e.target).attr('href');
var remoteUrl = $(this).attr('data-tab-remote');
var loadedOnce = $(this).data('loaded');
if (remoteUrl !== '' && !loadedOnce) {
$(currTabTarget).load(remoteUrl)
$(this).data('loaded',true);
}
})
Upvotes: 4
Reputation: 721
This would require you to make use of bootstrap tab's 'show.bs.tab' event. I'm not a rails guy but I've implemented similar behaviour in ASP.Net MVC - fetch the content of each tab dynamically on tab click using ajax. Since both emit HTML and we are using ajax, I reckon what worked for me will also work for you.
Here goes - I've added an extra attribute to the tabs 'data-tab-remote' and I register an event handler in jquery that fetches the tab content from the URL specified in the data-tab-remote attribute and populates it into the target tab-content container specified in the tab's href. So the emitted HTML for the tabs page would look something like this -
<ul class="nav nav-tabs" style="border-right:solid" id="tabs">
<li><a href="#tab1" data-toggle="tab" data-tab-remote="/tab1url">Tab1</a></li>
<li><a href="#tab2" data-toggle="tab" data-tab-remote="/tab2url">Tab2</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane fade" id="tab1">
</div>
<div class="tab-pane fade in active" id="tab2">
</div>
</div>
With this HTML, you'll need to call the below jQuery code in your document's on load event handler -
$('a[data-toggle="tab"]').on('show.bs.tab', function (e) {
currTabTarget = $(e.target).attr('href');
var remoteUrl = $(this).attr('data-tab-remote')
if (remoteUrl !== '') {
$(currTabTarget).load(remoteUrl)
}
})
Upvotes: 9