Hamid Fadishei's Blog

March 22, 2012

ZK MVVM Design Pattern and Server-Side Paging

Filed under: Java — fadishei @ 1:34 pm
Tags: , , ,

MVVM (Model/View/ViewModel) is a brilliant variant of the well known MVC (Model/View/Controller) design pattern. ZK has recently added support for this pattern. For an intruduction to MVVM in ZK you may want to see this page.
On the other hand, server-side paging is a technique for showing a huge list of records without fetching and transferring all the data from database to the client. ZK has some good documents and tutorials for implementing this technique using MVC pattern. But so far I could not find any good tutorial for pagination in MVVM projects. Thus I decided to have a short howto for that in my blog. I assume that you are familiar with ZK and Spring framework.
Assume you want to show a list of people in your rich Internet application. The Person POJO is defined as follows:

package ir.fadishei.examples.zk.paging.model;

public class Person
{
	Integer id;
	String firstName;
	String lastName;
	
	// Setters and getters come here
}

The example WITHOUT server-side paging

First, I show how you display the list of people without server-side paging. This will fetch all the records and transfer them to the client which is not a good idea in case of huge lists. I will use my favorite library, myBatis, for mapping between my sqlite person database table and the Person POJO. You may want to use other ones like Hibernate instead.

package ir.fadishei.examples.zk.paging.model;

import java.util.List;
import org.apache.ibatis.annotations.Select;

public interface PersonMapper
{
	@Select("SELECT * FROM person)
	List<Person> getPersons();
}

Now we write a ZUL page for displaying the people list:

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<zk>
<window title="List of people" border="normal" width="600px" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('ir.fadishei.examples.zk.paging.viewmodel.PersonVM')">
	<vbox hflex="true">
		<listbox model="@bind(vm.persons)" hflex="true" height="200px" mold="paging">
			<listhead>
				<listheader label="Id"/>
				<listheader label="First Name"/>
				<listheader label="Last Name"/>				
			</listhead>
			<template name="model" var="person">
				<listitem >
					<listcell label="@bind(person.id)"/>				
					<listcell label="@bind(person.firstName)"/>
					<listcell label="@bind(person.lastName)"/>
				</listitem>
			</template>
		</listbox>
	</vbox>
</window>
</zk>

Finally, we need the ViewModel for brdging the view to the model:

package ir.fadishei.examples.zk.paging.viewmodel;

import ir.fadishei.examples.zk.paging.model.Person;
import ir.fadishei.examples.zk.paging.model.PersonMapper;
import java.util.List;
import org.zkoss.zk.ui.select.annotation.WireVariable;

public class PersonVM
{
	@WireVariable
	PersonMapper personMapper;

	public List<Person> getPersons()
	{
		return personMapper.getPersons();
	}
}

The example with server-side paging

Now we modify the previous example for making it able to paginate at server side. First of all, we should change the database mapper to be able to fetch a specific page from person table. It should also have a method that returns the total number of records. This is required to find out the total number of pages displayed in the view:

package ir.fadishei.examples.zk.paging.model;

import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface PersonMapper
{
	@Select("SELECT * FROM person limit #{limit} offset #{offset}")
	List<Person> getPersonPage(@Param("offset") Integer offset, @Param("limit") Integer limit);

	@Select("SELECT COUNT(*) FROM person")
	Integer getPersonCount();
}

Next, we modify the view and remove the paging capability from the listbox. instead, we add a separate paging component:

<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<zk>
<window title="List of people" border="normal" width="600px" apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('ir.fadishei.examples.zk.paging.viewmodel.PersonVM')">
	<vbox hflex="true">
		<paging pageSize="@load(vm.pageSize)" totalSize="@load(vm.totalSize)" activePage="@save(vm.activePage)"/>
		<listbox model="@bind(vm.persons)" hflex="true" height="200px">
			<listhead>
				<listheader label="Id"/>
				<listheader label="First Name"/>
				<listheader label="Last Name"/>				
			</listhead>
			<template name="model" var="person">
				<listitem >
					<listcell label="@bind(person.id)"/>				
					<listcell label="@bind(person.firstName)"/>
					<listcell label="@bind(person.lastName)"/>
				</listitem>
			</template>
		</listbox>
	</vbox>
</window>
</zk>

Our ViewModel should get activePage from view and give pageSize, totalSize, and active page contents to the view:

package ir.fadishei.examples.zk.paging.viewmodel;

import ir.fadishei.examples.zk.paging.model.Person;
import ir.fadishei.examples.zk.paging.model.PersonMapper;
import java.util.List;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.select.annotation.WireVariable;

public class PersonVM
{
	int pageSize = 10;
	int activePage = 0;
	@WireVariable
	PersonMapper personMapper;
	
	public int getTotalSize()
	{
		return personMapper.getPersonCount();
	}
	
	public Integer getPageSize()
	{
		return pageSize;
	}

	@NotifyChange("persons")
	public void setActivePage(int activePage)
	{
		this.activePage = activePage;
	}

	public List<Person> getPersons()
	{
		return personMapper.getPersonPage(activePage*pageSize, pageSize);
	}
}

Alternatively, you could handle onPaging event of the paging component instead of binding its activePage to the ViewModel. But I think this would be a little messier!

Advertisements

9 Comments »

  1. Nice example but the stuff about mvvm is pretty new. Do you have an complete example, als also some configuration tips to get it working. I do not know the basic stuff for the doa and mapping ibatis to a sqlite.

    Comment by johnverberne — March 30, 2012 @ 1:28 pm | Reply

    • Thanks. I will upload the complete working example soon.

      Comment by fadishei — April 7, 2012 @ 6:57 am | Reply

  2. Great Great article… I just encourage you to publish it in the smalltalks section at zkoss.org… also there are other similar functionalities related to other rich components like smart autocomplete on combobox, search suggestions, etc…

    Comment by Iosvany — April 13, 2012 @ 6:22 pm | Reply

  3. Big big thanks!!
    Very well explained and a “must known” if you use Zkoss MVVM model.

    Comment by Janfran — May 3, 2012 @ 1:21 pm | Reply

  4. A great article. I followed this closely in creating a spring-data-mongodb demo application with serverside pagination. The demo code is zkmongomaps on github.com. I would encourage you to publish your code on github and republish this article on javalobby or the zkoss site as such work is very valuable to the opensource community. Thanks again.

    Comment by simbo1905 — December 28, 2012 @ 12:04 pm | Reply

  5. Really good one. Thanks Thanks a ,lot. But your last line “Alternatively, you could handle onPaging event of the paging component instead of binding its activePage to the ViewModel. But I think this would be a little messier!”, really confusing me whether to implement this method. You mean to say, your way of implementing is mess up when compare to alternate method. Can you please explain with an example on the other alternative method ?

    Comment by Senthil Muthiah — October 8, 2013 @ 12:34 pm | Reply

    • Thanks. I meant that I think the first approach is more clear. Unfortunately I am not able to explain the second approach for now, but believe me, the first one that I mentioned is better!

      Comment by fadishei — November 1, 2013 @ 1:58 pm | Reply

  6. good, but it’s verry well if have a demo

    Comment by Mr.Phuc — March 17, 2014 @ 2:08 am | Reply


RSS feed for comments on this post. TrackBack URI

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

Create a free website or blog at WordPress.com.

%d bloggers like this: