Paging

Release 1.0 - ...

Especially when formatting large result sets, paging can be essential. Not only does it limit the amount of information displayed on the screen, but it also limits the load on the server.

Paging can be done in several ways, but one simple and generic way comes right out of the box, using the paging macro:

Datatable based paging

Smartsite SXML CopyCode image Copy Code
<se:xlinks save="table" resulttype="datatable" parent="3817"/>
 
<se:paging id="paging" 
 inputdata="table"
 pagesize="5"
/>
 
<se:format inputdata="table"
 maxrows="{page.paging.size()}"
 skiprows="{page.paging.skip()}"  >
 <se:rowformat>
  <li><a href="{this.location()}">{this.field(title)} </a></li>
 </se:rowformat>
 <se:resultformat>
  <ul>{this.result()} </ul>
 </se:resultformat>
</se:format>
 
<span class="navbar">
 {page.paging.goto(First)} 
 {page.paging.goto(Previous)}
 {page.paging.goto(Next)}
 {page.paging.goto(Last)}
 {page.paging.current()} / {page.paging.count()}
</span>

Now, many of you will argue that the datatable used for paging will be created and filled with all records each roundtrip, and you're right: this isn't the most efficient way...

Cached Datatable based paging

The cache macro can help here. Simply by wrapping the query in cache and storing the cache key into a buffer, the datatable is stored into cache and can be re-used for each page displayed:

Smartsite SXML CopyCode image Copy Code
<se:cache save="key = this.getcachekey()" resulttype="none" >
 <se:xlinks resulttype="datatable" parent="3817"/>
</se:cache>
 
<se:paging id="paging" 
 inputdata="key"
 pagesize="5"
/>
 
<se:format inputdata="key"
 maxrows="{page.paging.size()}"
 skiprows="{page.paging.skip()}"  >
 <se:rowformat>
  <li><a href="{this.location()}">{this.field(title)} </a></li>
 </se:rowformat>
 <se:resultformat>
  <ul>{this.result()} </ul>
 </se:resultformat>
</se:format>
 
<span class="navbar">
 {page.paging.goto(First)} 
 {page.paging.goto(Previous)}
 {page.paging.goto(Next)}
 {page.paging.goto(Last)}
 {page.paging.current()} / {page.paging.count()}
</span>

Paged sql query based paging

Using the sqlquery macro, you can even page at the very source, by creating paged queries, for instance by using the row_number() function and the over() clause.

The PagingId property can be used to let SqlQuery autogenerate a paging query. At this point it has been tested with SqlServer 2005.

Smartsite SXML CopyCode image Copy Code
{buffer.set(history, 30)}
 
<se:paging
 rem="State machine for recent edits"
 id="recent"
 pagesize="10"
/>
 
<se:sqlquery save="list" pagingid="recent">
 <se:parameters>
  <se:parameter name="sql">
   select c.nr, c.title, c.moddate, u.fullname
    from {channel.view()} c 
    join vwUsers u on c.userid=u.nr
    where getdate()-c.moddate {char.lt()} ?:p1 order by moddate desc 
  </se:parameter>
  <se:parameter name="params">
   <se:collection>
    <se:member name="p1">{buffer.get(history)}</se:member>
   </se:collection>
  </se:parameter>
  <se:parameter name="format">
   <se:rowformat>
     <li>
      <a href="{this.location()}">{this.name()}</a><br />
      <small>{datetime.format(this.field(moddate), 'd MMM yyyy, HH:mm')} by {this.field(fullname, default='unknown author')} </small>
     </li>
   </se:rowformat>
  </se:parameter>
  <se:parameter name="resultformat">
   <h3>Recent edits (last {buffer.get(history)} days)</h3>
     <ul>
      {this.result()}
     </ul>
     <div class="navbar">
      {page.recent.goto(First)}
      {page.recent.goto(Previous)}
      {page.recent.goto(Next)}
      {page.recent.goto(Last)}
     </div>
  </se:parameter>
 </se:parameters>
</se:sqlquery>

Conclusion

The paging macro provides a simple and generic paging state model that can be implemented with minimal effort, both with any saved datatable and with efficient sql-based paging syntax.