3
\$\begingroup\$

I'm working in an application where there's a long unordered list of items that have to be paginated. New items are added to the list regularly, and the items come from a database.

The only control I have is via the front end. I cannot control how they are all loaded in the DOM before page load.

I was able to work this out using Ben Everard's jqPagination plugin.

All list items are hidden with display:none. Then, when the next/previous buttons are clicked, a group of items are given the 'active' class - which sets them to display:block.

 //get the total number 
 var maxItems = $('li').length,
 numPages = maxItems / 5,
 oldSet,
 pageSet = 5; 
 function showPages(s,c) {
 $('li').slice(s, c).addClass('active'); 
 pageSet = c; 
 }
 $(document).ready(function() {
 //Show first set of items 
 showPages(0, pageSet);
 $('.pagination').jqPagination({
 max_page : Math.ceil(numPages),
 paged : function(page) {
 //Remove the active class from previously active items
 $('.active').removeClass('active');
 //Reset the pageSet number 
 pageSet = 5 * page;
 oldSet = pageSet - 5;
 showPages(oldSet, pageSet); 
 }
 });
 });

This works pretty fast as is, but I'm concerned about whether it will run slow once the list grows (say to 1200 items).

How could I prevent any performance issues? Is it unavoidable?

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Mar 4, 2015 at 20:58
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

You can't totally guarantee performance here, since so much is up to how the browser handles DOM manipulation and reflowing content when it's shown/hidden. But there are some things you can improve. Most notably: Don't find and re-find all the elements every time the page changes.

But first, in terms of structure, there's something weird going on. Only the jqPagination stuff is inside a $(document).ready() callback. Yet you're also trying to access page elements before that. The whole point of the ready event is that it fires when you can start using the DOM; if you try before that, the page might not have finished loading. So the browser might literally only have half the page, with the rest still on its way across the interwebs.

So when you do this:

var maxItems = $('li').length

you risk finding zero li elements, because the page isn't ready yet.

Secondly, I worry about the way you're selecting elements. $('li') will select all list item elements anywhere on the page. Doesn't matter if they're part of the list you want to paginate or not. In other words, you're selector casts its net much too wide.

Similarly with the $('active').removeClass('active'); call. Again, that's selecting any element with the active class, regardless of where it is on the page. Using a class named active is a pretty common thing for highlighting links, buttons, and tons of other things. So that line could easily wreak havoc on other parts of the page. Again, too greedy a selector.

Incidentally, I'd also use an ID of the list-pagination buttons, if there's only that one list. Having multiple elements with the class pagination is perhaps less common, but your code certainly doesn't expect more than one, so better to use an ID, which is what you'd use for unique, non-repeated elements.

Back to structure: Your code is split in two. You have the showPage function, which does indeed show pages. But the code to hide the previous page (the removeClass call), is somewhere else. Why? If I call showPage I'd expect it to show a page. Not just show the requested page, and leave previous stuff around. You're also calculating some stuff before calling showPage, despite it being able to do so itself.

In other words, you've added a function, but not given it all the functionality it should probably have.

Finally, you have 5 as a magic number repeated in multiple places. Stick it in a variable and reference that variable instead. That way we a) know what the number is (it's got a name now), and b) you only have to change it in one spot to change the behavior. When it's spread out, maintenance becomes much harder.

I'd do this:

$(function () { // equivalent to $(document).ready(...)
 var perPage = 5,
 allItems = $('#theBigList').children('li'), // change to fit your list's selector
 previousItems = null; // stores the last set of elements
 // a simpler implementation
 function goToPage(page) {
 var offset = (page - 1) * perPage;
 // hide previous items, if any
 if(previousItems) {
 previousItems.removeClass('active');
 }
 // show new items, and store the set
 previousItems = allItems.slice(offset, perPage).addClass('active');
 }
 $('#paginationControls').jqPagination({
 maxPage: Math.ceil(allItems.length / perPage),
 paged: goToPage
 });
 goToPage(1); // might not be necessary if jqPagination automatically invokes its "paged" callback with the argument 1 upon initialization
});

Again, though, if things slow down for very long lists, it's probably because they're very, very long lists. It's not really the javascript that's at fault; it's how fast the browser is.

answered Oct 21, 2015 at 21:42
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.