0

I have a Ruby on Rails app with some jquery to render partials asynchroneously. So first I want to change to active state of the tabs, then clear the tab pages and then load the partial:

  $('#availability').addClass('active');
  $('#overview').removeClass('active');
  $('#availabilityTab').addClass('active').addClass('in');
  $('#overviewTab').removeClass('active').removeClass('in');
  $("#availabilityTab").html("<%= escape_javascript(render(partial: 'availability')) %>");

This works fine, however when I click the tab to trigger this, I expect to see a blank tabpage first and the the loaded data. What happens is when the tab is clicked, nothing seems to happen and then after 3 seconds the partials shows up. This is because the database call takes a while (needs to be optimized :-) ). This is confusing for the user, I rather want to see an empty tab page first. How can I do this?

Update: This is how the controller action looks like:

  def index
    @customers = Customer.order(:name)
    @target = params[:target] unless params[:target].blank?

    respond_to do |format|
      format.html
      format.js
    end
  end

And this is index.js.erb:

<% if @target == "overview" -%>
  $('#availability').removeClass('active');
  $('#overview').addClass('active');
  $('#overviewTab').addClass('active').addClass('in');
  $('#availabilityTab').removeClass('active').removeClass('in');
  $("#overviewTab").empty().html("<%= escape_javascript(render(partial: 'overview')) %>");
<% elsif @target == "availability" -%>
  $('#availability').addClass('active');
  $('#overview').removeClass('active');
  $('#availabilityTab').addClass('active').addClass('in');
  $('#overviewTab').removeClass('active').removeClass('in');
  $("#availabilityTab").html("<%= escape_javascript(render(partial: 'availability')) %>");
<% end %>
John
  • 6,404
  • 14
  • 54
  • 106

1 Answers1

0

Seems to me that you're using async: false in Ajax (this freezes the browser until the request completes)

Even if this is not the case, your effects are dependent on your db call, which is why you're experiencing the lag. To fix this, you either need to reconfigure your system to work around Ajax, or you need to trigger your effects as naturally as possible (I.E in the backend after the db call has been processed)

Here are two ways to look at it:


Ajax Callbacks

wait for a jquery ajax callback from calling function

We successfully use Ajax Callbacks to load partials in one of our production apps, here's how we do it:

 //app/assets/application.js
 $(".your_element").on("click", function() {
     fetch_modal("link", function(data){
         //success
     , function(data) {
         //error
     });
 });

 //Ajax
 function fetch_modal(link, success, error) {
   $.ajax({
      url: link,
      success: function(data) { success(data); },
      error: function(data)   { error(data); }
   });
 }  

This will not freeze the browser, and works synchronously

I have a script which calls partials through Ajax using this technique if you'd like the link. I have been meaning to publish it


Processing After The DB Call

One reason you're seeing these problems if you're calling the JS after the event, not the result

To remedy this, I'd look at putting the "effect" code after the JS has been processed, like this:

#app/controllers/example_controller.rb
def example
    @example = Example.find(1)

    respond_to do |format|
        format.html { redirect_to root_path }
        format.js 
    end
end

#app/views/example/example.js.erb
# Only fires after the DB call
$('#availability').addClass('active');
$('#overview').removeClass('active');
$('#availabilityTab').addClass('active').addClass('in');
$('#overviewTab').removeClass('active').removeClass('in');
$("#availabilityTab").html("<%= escape_javascript(render(partial: 'availability')) %>");
Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • Thanks for your comprehensive answer! I do like the second solution, but do'n really get what you mean with "# Only fires after the DB call". It seems to me that the lines of jquery code is exactly the same as mine? I have updated my question with more information. – John Jan 17 '14 at 07:54
  • Hey John - I meant that it only fires after Rails has performed it's query, not when you've performed an event in JS. The different is that after the query will mean your app will show a "loading" icon for as long as the query is performed, and then the different classes are applied – Richard Peck Jan 17 '14 at 09:04