简体   繁体   中英

How do I render a partial asynchronously/using AJAX in Rails?

I currently have the following code to load a partial when I scroll to the bottom of a div with a table:

$(document).ready(function () {
        $("#pastGigs").scroll(function () {
            if (isScrollBottom()) {
                $('#pastGigs tr:last').after('<%= render "layouts/pastGigs" %>');

                $(this).unbind("scroll");
            }
        });

        function isScrollBottom() {

            var elementHeight = $("#pastGigs")[0].scrollHeight;
            var scrollPosition = $("#pastGigs").height() + $("#pastGigs").scrollTop();
            return (elementHeight == scrollPosition);
        };

    });

It works fine, but the reason I'm using the partial is because I don't want everything to load immediately, as it really slows the page down. Should I not be using a partial at all, or is there another way to execute the script and load the content only after scrolling? I've had a look around similar questions on stackoverflow, they all explain how to render the partial (I didn't know about escape_javascript and deleted all whitespace in the partial manually...), but none seem to solve my current speed issue. There is a difference of about 15 seconds (!) due to the amount of data in the partial, which is why I don't want to load it synchronously.

EDIT: Current config/routes.rb:

root "resnate_pages#home"
resources :users, :path => ''

EDIT 2: Current error in Terminal:

Processing by UsersController#show as */*
Parameters: {"id"=>"pastGigs"}
User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1  [["id", "pastGigs"]]
Completed 404 Not Found in 3ms

ActiveRecord::RecordNotFound (Couldn't find User with id=pastGigs):
app/controllers/users_controller.rb:5:in `show'

After looking over everything, it looks like you have the right idea with rendering the partial except that, as we discussed, it is not actually being loaded asynchronously. Since you have the ERB tags in the body of the javascript, the ERB is actually being rendered server-side before being delivered to the browser (as you noticed, with the huge blob of HTML text). The reason this appeared to work (meaning avoiding the huge 15-second load times you mentioned) is because the HTML text isn't actually interpreted as HTML yet by the browser when the page loads (its just a plain 'ol string at this point). It will of course be parsed and evaluated when you do add it to the DOM with the .after function.

So basically we just need to ajax this stuff up. Good that you're looking at the jQuery ajax documentation; definitely worth the time and its pretty informative. There is also a $.get function which you might want to see as well. Its a convenience method for sending a GET request; you have less control, but if that doesn't matter, it can help keep things clean. I'll demonstrate with the $.get function, and you can choose to use the $.ajax function instead if you need the control (or prefer the other).

Put this in your scroll function:

$("#pastGigs").scroll(function () {
    if (isScrollBottom()) {

        $.get("/pastGigs", function(result){
            $('#pastGigs tr:last').after(result);
        });

        $(this).unbind("scroll");
    }
});

You can name the pastGigs route however you like, its only for demonstration purposes. Ensure you set up the route in your routes.rb

get "/pastGigs" => "users#pastGigs"

OR

get "/pastGigs", to: "users#pastGigs"

Again, I don't know what your controller is called, so replace it and the action name with the correct ones in your system.

And finally, the controller action:

def pastGigs
   render :partial => "layouts/pastGigs"
   # OR
   # render "layouts/pastGigs", :layout => false
end

The end result will be that when the scroll reaches the bottom, an ajax call is fired off to that URL and your partial is rendered and returned to the success function (the second parameter of $.get ). The result variable will contain the rendered HTML partial.

Let me know if that works.

Quickly adapted Paul's code to populate a modal for anyone who's interested:

$('#seeAll').click(function(){
$.get("/pastGigs", function(result){
$('#pastGigsBody').html(result);});
});

When the user clicks on "See All" in the Past Gigs div, it opens the modal with the all of the past gigs. Thanks to Paul for teaching me about the $.get request.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM