The Kahimyang Project Logo
Primo's Code Blog
Howtos tips and tricks
The Kahimyang Project

Creating a Facebook-like panel with slim scrollbars and infinite scrolling in PrimeFaces

Some of the Facebook panels with slim scrollbars and infinite scrolling are those non full-page panels used to display notifications and messages. These are activated by button-icons in the upper left corner of your timeline. In this blog, we will demonstrate how to create similar panels using slimScroll jQuery plugin in PrimeFaces.

Please note that the first section of this blog (slimScroll panel without the infinite scrolling) also works for standard JSF projects.

The slimScroll Panel

The first step in building our slimScroll panel is to load slimScroll plugin.  Download the plugin itself from the link mentioned above and add them to the head section of the page similar to what is shown below.

<!-- jQuery itself for non PrimeFaces only, jQuery is bundled in PrimeFaces -->
<script type="text/javascript" 
     src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
</script>
<script type="text/javascript" 
     src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.js">
</script>
<!-- End jQuery itself -->

<-- slimScroll plugin -->
<script type="text/javascript" src="/kauswagan/js/jquery.slimscroll.min.js">
</script>

Attach slimScroll to an element.  In our example below, we attach slimScroll to an element with class most_slim.  Our panel has width of 300px and height of 400px.  The slim scrollBar appears only when we hover above it and fades out if we stay idle over the scrollable area.  This behaviour is similar to Facebook's.  Please refer to slimScroll documentation for more options.

<script>          
    $(function(){
        $('.most_slim').slimScroll({
            height: '400px',
            disableFadeOut: false,
            width:'300px',
            railVisible: true,
            alwaysVisible: false
        });
    });            
</script>

The markup structure below defines our most_slim panel which wraps a <h:dataTable /> our scrollable content component.  We also used <h:panelGroup /> with block layout so that JSF will generate a <div /> instead of <span />.  Notice that our most_slim panel is in turn wrapped with another <h:panelGroup />.  This is the parent of our most_slim, it is required.

<h:panelGroup style="border:1px solid #bbdddd;">
    <h:panelGroup  styleClass="most_slim" layout="block" >
        <h:dataTable  style="width:290px;" cellpadding="5" 
                      rowClasses="row_2a,row_2b"  
                      value="#{facebookBean.records}"
                      var="facebook">
            <h:column>
                <h:outputLink  value="#{newsObject.seoId}" >
                    <h:outputText escape="false" 
                           value="#{facebook.title}" />
                </h:outputLink>

            </h:column>

            <h:column>
                <h:outputText value="#{facebook.views}" escape="false" /> 
            </h:column> 
        </h:dataTable>
    </h:panelGroup>
</h:panelGroup>

Our <h:dataTable /> has a width of 290px and our most_slim has 300px.  This is to give room for the scrollBar and rail, so that it does not draw itself over the content.

For our <h:dataTable /> above to be populated with data, your backing bean (FaceBookBean in this example) should have a method List getRecords (), this is set as value #{facebookBean.records} in <h:dataTable />.  Please see further down this page for details of this bean.

At this point we already have a working panel with slim scrollBars.  This panel we just created works for both PrimeFaces and also for standard JSF projects.

Infinite scrolling demonstrated after this point, works only for PrimeFaces.

slimscroll Panel with infinite scroll

Below is the same snippet we used for the scroll panel we earlier created with slimScroll, only we added line 11 and below.  Note that in the snippet below, some user prefer to chain the two calls below, appending bind to the first call (see a chaining example near the bottom of this article).

<script>          
    $(function(){
        $('.most_slim').slimScroll({
            height: '400px',
            disableFadeOut: false,
            width:'300px',
            railVisible: true,
            alwaysVisible: false
        });

        $('.most_slim').slimScroll().bind('slimscroll', function(event, pos){
            if (pos == 'bottom') {
                more_records();
            }
        });            
    }); 
</script>

slimScroll publishes an event when either the top or bottom of the scrollable panel is reached.  In line 11 above we bind to this event to update our panel to implement our infinite scroll.  To accomplish this infinite scrolling, we add PrimeFaces' <p:remoteCommand /> (line 28 below).

more_records in line 13 above, is the name of our <p:remoteCommand />.  This gets executed as soon as we reach the bottom of the scrollable area.  The body of the JavaScript function more_records is empty, it has no body, PrimeFaces generates its body for us, at runtime.

The actionListener (line 32 below) also gets executed as more_records executes, updating our slim_panel which is our <h:dataTable />.

<h:panelGroup style="border:1px solid #bbdddd;">
    <h:form prependId="false">
        <h:panelGroup  styleClass="most_slim" layout="block" > 
            <h:dataTable id="slim_panel"  style="width:290px;" cellpadding="5" 
                         rowClasses="row_2a,row_2b"  
                         value="#{facebookBean.records}"
                         var="facebook">
                <h:column>
                    <h:outputLink  value="#{newsObject.seoId}" >
                        <h:outputText escape="false" 
                                      value="#{facebook.title}" />
                    </h:outputLink>
                </h:column>

                <h:column>
                    <h:outputText value="#{facebook.views}" escape="false" 
                          style="font-size: 11px;font-weight: normal;" />
                </h:column> 
            </h:dataTable>
        </h:panelGroup>

        <h:panelGrid columns="2" style="width:100%;padding:7px;margin-top: 3px;">
            <h:outputText value="Recent posts" />
            <h:graphicImage style="display:none;width:15px;" 
                 id="preloader" value="/images/prog.gif" />
        </h:panelGrid>

        <p:remoteCommand global="false" name="more_records"   
                         onstart="$('#preloader').show();"
                         oncomplete="$('#preloader').hide();"
                         update="slim_panel"
                         actionListener="#{facebookBean.loadMore}" />

    </h:form>
</h:panelGroup>

LIne 22 to 26 above is just the holder of the preloader image.  The preloader visiblity is controlled by onstart and oncomplete events of <p:remoteCommand />.

Below is the backing bean of the page snippet above.  We included this to highlight line 19 below, our loadMore function called by <p:remoteCommand />.  Notice that each time the function is called, which corresponds to each time our slimScroll hits the bottom of the scrollable area, endLimit is incremented and returns more data to our <h:dataTable />.  Also for this to work, the bean must be either SessionScoped or ViewScoped so that endLimit keeps its value.

@ManagedBean
@ViewScoped
public class FacebookBean implements java.io.Serializable {

    FacebookBean () {}
    
    private List<PostRecord> records;
    
    public List<PostRecord> getRecords() {
        if (records == null) {
            records = theRecords(0, endLimit);
        }
        return records;
    }

    // endLimit is the end limit of an SQL query of limit clause 
    private int endLimit = 20;
    
    public void loadMore() {        
        endLimit += 10; // Change this value to suit your needs.       
        records = theRecords(0, endLimit);
    }

    List<PostRecord>theRecords(int start, int end) {
        List<PostRecord>list = new ArrayList<>();

        // Database Query, 
        // Select statement should have a limit clause
        // using the start and end parameters of
        // this method.

        while (loop through database records) {
            PostRecord rec = new PostRecord ();
            //
            // more code
            //
            list.add (rec);
        }
        // Some code were removed for clarity.
        
        return list;
    }

    // Some lines were removed for clarity.

    public static class PostRecord implements java.io.Serializable {
        String title;
        String views;

        // getters and setters here
    }
}

Notes on infinite scroll

As more data is loaded into our scrollable panel, the scrollBar will be shorter and tends to stay near or at the bottom of the panel.  At that point infinite scroll may stop working.  For scrolling to continue working, move away from the bottom either by user action or programmatically.  See line 11 below.

<script>          
    $(function(){
        $('.most_slim').slimScroll({
            height: '400px',
            disableFadeOut: false,
            width:'300px',
            railVisible: true,
            alwaysVisible: false
        }).bind('slimscroll', function(event, pos){
            if (pos == 'bottom') {
                $('.most_slim').slimScroll({ scrollBy: '-60px' });
                more_records();
            }
        });            
    }); 
</script>

What we have above is the same snippet we have earlier, only we added line 11 to scroll away from the bottom.  In this example we used 60px of scroll back. Change this value to suit your needs.  This snippet also illustrates chaining.

That's it Good Luck.

RSS Logo



Related articles

Comment icon   Comments (Newest first)

Recent posts in Java/JSF category
Blue dot icon Using Rhinoslider with image and youtube content in JSF pages
Blue dot icon A dynamic standard sitemap.xml with Google image extension implemented as a Java Servlet
Blue dot icon Creating a Facebook-like panel with slim scrollbars and infinite scrolling in PrimeFaces
Blue dot icon Generating XML RSS 2 feeds with JDOM 2 with a servlet
Blue dot icon Building a page with infinite scroll in PrimeFaces using Waypoints jQuery plugin
Blue dot icon Implementing a collapsible ui:repeat rows in JSF
Blue dot icon Validating an email address in PrimeFaces p:inputText field with p:ajax





Most popular articles
Blue dot icon Using Expect script to automate SSH logins and do routine tasks accross multiple hosts   (15378)
Blue dot icon How to setup Tomcat 7 as your primary webserver on Debian Squeeze    (14076)
Blue dot icon How to setup FLV streaming with crtmpserver C++ RTMP server   (9848)
Blue dot icon A Java class for sending multipart Email messages through your Gmail account    (6979)
Blue dot icon How to use Google Translate's Text to Speech (TTS) services in your web page using Servlet   (5674)
Blue dot icon Speed up Primefaces page load with p:remoteCommand partial update   (5501)
Blue dot icon Building a mobile website with JSF 2 core and JQuery Mobile 1.0   (5322)
Blue dot icon Google Map-Adding markers, info window, circle, small control, and events in Javascript    (5226)