Brandon Durham
Brandon Durham

Reputation: 7717

Need to loop through 500+ table rows and browser is choking

I've got a large table that lists out approximately 50 users and some simple data around their accounts, including the number of "projects" they have. When clicking on a user row more rows expand beneath to reveal detailed information about each of their projects. Most users have fewer than 20 projects, so it's not terribly taxing on the browser. However, there are a few users that have 100+ projects (one with 500+) and when clicking on the user row the browser stalls for anywhere from 1-4 seconds.

The table rows are set up so that any row with the .project class is hidden by default, and when clicking on a user row (no .project class) all subsequent rows with the .project class have the class .open added which displays them.

Suggestions on how to make this run faster? Is there a better, cleaner way to achieve the same effect?

Here is a simplified version of the HTML:

<table>
    <tr>
        <td>Username</td><td>Email</td><td>10 Projects</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr>
        <td>Username</td><td>Email</td><td>3 Projects</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
    <tr class="project">
        <td>&nbsp;</td><td>&nbsp;</td><td>Project Name</td>
    </tr>
</table>

... and the JS:

(function($) {

    $.fn.viewProjects = function() {

        this.each(function() {
            $(this).click(function(){

                var projects = $(this).nextUntil(':not(.project)'); // get all rows that follow and have the '.project' class

                if ($(this).hasClass('focused')) { // collapse
                    $(this).removeClass('focused');
                    projects.each(function(n, proj){
                        $(proj).removeClass('open');
                    });
                }
                else { // expand
                    $(this).addClass('focused');
                    projects.each(function(n, proj){
                        $(proj).addClass('open');
                    });
                }

            });
        });

    };

    $('tr:not(.project)').viewProjects();

})(jQuery);

Upvotes: 0

Views: 130

Answers (4)

BumbleB2na
BumbleB2na

Reputation: 10743

This is because the DOM is loading so much added stuff in to it. What I do in similar situations is:

  • Check if there are more than 50 rows
  • If so, then stop at 50 and place a "click to view more" link.
  • When clicked, load the next 50 rows.
  • Continue this process until all rows are loaded.

Alternatively, you can automatically trigger the next 50 rows to load when the user scrolls down the page. I prefer showing a link because automatically loading stuff can be confusing.

Edit - What if you use jQuery to show and hide the contents instead of adding and removing a class each time?

if ($(this).hasClass('focused')) { // collapse
    $(this).removeClass('focused');
    projects.hide();
} 
else { // expand
    $(this).addClass('focused');
    projects.show();
}

Upvotes: 2

steveax
steveax

Reputation: 17743

Instead of showing/hiding 500 items, show/hide one:

Restructure the HTML into something like this:

<table>
    <tr>
        <td>Username</td><td>Email</td><td>10 Projects</td>
    </tr>
    <tr class="project">
        <td colspan="3">
            <ul>
                <li>Project Name</li>
                <li>Project Name</li>
                <li>Project Name</li>
                <li>Project Name</li>
                <li>Project Name</li>
                <li>Project Name</li>
                <li>Project Name</li>
                <li>Project Name</li>
                <li>Project Name</li>
        </ul>
    </td>
</tr>

Upvotes: 0

Liam
Liam

Reputation: 29714

You don't need the each. the click function in Jquery is chainable This may speed it up:

(function($) {

    $.fn.viewProjects = function() {

            $(this).click(function(){

                var projects = $(this).nextUntil(':not(.project)'); // get all rows that follow and have the '.project' class

                if ($(this).hasClass('focused')) { // collapse
                    $(this).removeClass('focused');
                    projects.each(function(n, proj){
                        $(proj).removeClass('open');
                    });
                }
                else { // expand
                    $(this).addClass('focused');
                    projects.each(function(n, proj){
                        $(proj).addClass('open');
                    });
                }

            });

    };

    $('tr:not(.project)').viewProjects();

})(jQuery);

Upvotes: 0

18bytes
18bytes

Reputation: 6029

You can check webworker to create threads to improve performance. I know this is a vague one, but i want to suggest this direction.

Unfortunately we cannot manipulate DOM inside webworkers. But DOM can be manipulated on your client code.

It appears that you are making XMLhttprequest to get new data, and this can be done inside webworkers.

Upvotes: 0

Related Questions