Putting some masonry and infinite scrolling on top

(see previous posts for context)

But if I started adding jQuery to the project, how about a fancy effects thing to show me the datatable in a funnier way? Like a… masonry layout? You know, small boxes floating around and rearranging themselves?

Enter Isotope. For this however I’d need to rewrite the table as a bunch of DIVs so isotope can shuffle them for me.

Here’s the new list.html:

<link rel="stylesheet" media="screen" href="../../styles/new.css" th:href="@{/styles/new.css}" />
</head>

<body>
    <div id="container">
        <div th:include="blocks :: header"></div>
        <div>
            <h2 th:text="#{entity_list_all(#{label_com_thymetest_domain_person_plural})}">Listing persons</h2>
        </div>
        <div th:include="blocks :: menu">Menu</div>
        <div th:each="guy : ${people}" th:object="${guy}">
            <span style="font-size: 2em;" th:text="${guy.id} ">1 </span> <span> <a href="/thymetest"
                th:href="@{'/people/'+${guy.id}}"><img src="../../../images/show.png" alt="Show"
                    th:src="@{/images/show.png}" /></a> <a href="/thymetest" th:href="@{'/people/'+${guy.id}(form)}"><img
                    src="../../../images/update.png" alt="Update" th:src="@{/images/update.png}" /></a>
            </span><br /> <span th:text="*{fullName}">Geppetto Au</span><br /> <span th:text="*{socialId}">2349876234</span><br />
            <span th:text="*{email}">get@dis.rd</span>
        </div>
        <div th:include="blocks :: paginationbar">Pagination</div>
    </div>
</body>

As promised, I gave up on the table and used Thymeleaf to create me a set of DIVs for each data row. Even the header, menu and pagination footer can be DIVs, why not, so they can be shuffled around as well. Do you notice the few new CSS classes? Here they are, in a new CSS file:

.item {
    margin: 10px;
    padding: 5px;
    float: left;
}
.menu {
    background-color: #77AB59;
    color: #F0F7DA;
}
.menu a:link{
    background-color: #77AB59;
    color: #F0F7DA;
}
.content {
    background-color: #C9DF8A;
}
body {
    background-color: #F0F7DA;
    color: #234D20;
    font-family: "Trebuchet MS", Helvetica, sans-serif;
}

I used as color palette the nice and appropriately called “Spring Wedding” by Wolftlou (here it is, on ColourLovers) and gave the “system elements” (menu and paginator that is) a different style. It will certainly not win any design contest (except for the palette which is not mine anyway), but shows the point. Now the integration code:

<script type="text/javascript" src="../../scripts/jquery-1.7.1.min.js" th:src="@{/scripts/jquery-1.7.1.min.js}"></script>
<script type="text/javascript" src="../../scripts/jquery.isotope.js" th:src="@{/scripts/jquery.isotope.js}"></script>
<script type="text/javascript">
                $(function() {
                    var $container = $('#container');
                     $container.isotope({
                        itemSelector : '.item',
                        layoutMode : 'masonry',
                        masonry : {
                            columnWidth : 20
                        },
                        animationEngine : 'jquery'
                    });
                });
            </script>

One bug I noticed is that when I restore the browser window size the first time, it overlaps some squares (always the same, the silly). Well, it’s not a paid application lucky me, and further resizes shuffle the blocks properly.

infscroll0

But how about adding infinite scrolling? Well, it shouldn’t be that difficult should it – there’s an example on the Isotope site, and the code is pretty straightforward. Change your script section on the list.html like this:

<script type="text/javascript" src="../../scripts/jquery.infinitescroll.js"
        th:src="@{/scripts/jquery.infinitescroll.js}"></script>
<script type="text/javascript">
                $(function() {
                    var $container = $('#container');
                    $container.isotope({
                        itemSelector : '.item',
                        layoutMode : 'masonry',
                        masonry : {
                            columnWidth : 20
                        },
                        animationEngine : 'jquery'
                    });
                    $container.infinitescroll({
                        navSelector : '#next', // selector for the paged navigation 
                        nextSelector : '#next a', // selector for the NEXT link (to page 2)
                        itemSelector : '.item', // selector for all items you'll retrieve
                        loading : {
                            finishedMsg : 'No more pages to load.',
                            img : 'http://i.imgur.com/qkKy8.gif'
                        }
                    },
                    // call Isotope as a callback
                    function(newElements) {
                        $container.isotope('appended', $(newElements));
                    });
                });
            </script>

Of course, you’ll have also to point the scroll script to the right “next” anchor via navSelector/nextSelector so go to your blocks.html and add an id to the next link in the pagination block:

<li id="next" th:class="${actualPage ge maxPages}? 'disabled' : ''">

Then run your project and resize the window so you have room to scroll. Scroll down, does it work? Duh… kind of:

infscroll1

First of all, it adds the header and menu once again per each reload; secondly, it never stops adding empty pages when done with the elements. Whyyyyy…………

Why: the JS code grabs the “next” path at the very first run (aka, first load of the page) and stores it, so hiding or renaming the “next” link will not bring anything. But wait, why did I tell InfiniteScroll to handle all items? Of course it adds the header again and again – a request to page 892349876 will of course bring the basic template with no data but enough DIVs (correct: header, menu…). How about telling it to request only the data? Should have been obvious… here’s the new itemSelector for infinite scrolling:

  $container.infinitescroll({
      navSelector : '#next', // selector for the paged navigation 
      nextSelector : '#next a', // selector for the NEXT link (to page 2)
      itemSelector : '.content', // selector for all items you'll retrieve
      loading : {
          finishedMsg : 'No more pages to load.',
          img : 'http://i.imgur.com/qkKy8.gif'
      }
  },

and, that was it! It will even hide the “next” anchor when you reached the last page – although I’d rather hide the whole pagination element… and I’ve never seen that finished message, or the loading image… but whatever.

Useful links:

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s