Theme:
Description & Source Code

This sample demonstrates how to easily group data in grid using ZK's utility class org.zkoss.zul.GroupModelArray (prior to 5.0.5, use org.zkoss.zul.ArrayGroupsModel). The GroupsModelArray takes a data array and automatically creates groups (org.zkoss.zul.Group) of data based on the logic provided in a comparator class.

For generating data of Groupfoot, this demo use AdvancedGroupModelArray instead.

To render the data we utilise ZK's powerful databinding mechanism and inbuilt template support to render items depends on whether it is a groupheader, groupfooter or item. The templates to do this are clearly shown in "grouping_model_view.zul". The following image shows how ZK handles teh data using the GroupModelArray. When the process hits the Renderer stage this is when the rendering responsibility is passed to the binder.


This feature requires ZK PE or EE.
<zk>
	<div apply="org.zkoss.bind.BindComposer"
		viewModel="@id('vm') @init('demo.grid.grouping_model.FoodGroupViewModel')">
		<style src="/widgets/grid/grouping_model/Style.css" />
		<grid id="demoGrid" height="400px"
			model="@load(vm.foodModel)">
			<columns menupopup="auto">
				<column width="150px" sort="auto(Name)" label="Name" />
				<column hflex="1" sort="auto(TopNutrients)"
					label="Top Nutrients" />
				<column hflex="1" align="center"
					sort="auto(DailyPercent)" label="% of Daily" />
				<column hflex="1" align="center" sort="auto(Calories)"
					label="Calories" />
				<column sort="auto(Quantity)" label="Quantity" />
			</columns>

			<template name="model:group">
				<group label="@load(each)" />
			</template>
			<template name="model">
				<row>
					<label value="@load(each.name)" />
					<label value="@load(each.topNutrients)" />
					<label value="@load(each.dailyPercent)" />
					<label value="@load(each.calories)" />
					<label value="@load(each.quantity)" />
				</row>
			</template>
			<template name="model:groupfoot">
				<groupfoot>
					<cell colspan="5"
						style="text-align: right; padding-right: 15px">
						<label value="@load(each)"
							style="font-weight:bold;" />
					</cell>
				</groupfoot>
			</template>
		</grid>
	</div>
</zk>
package demo.data.pojo;

public class Food {
	private String Category;
	private String Name;
	private String TopNutrients;
	private Integer DailyPercent;
	private Integer Calories;
	private String Quantity;

	public Food(String category, String name, String topNutrients, Integer dailyPercent, Integer calories, String quantity) {
		super();
		Category = category;
		Name = name;
		TopNutrients = topNutrients;
		DailyPercent = dailyPercent;
		Calories = calories;
		Quantity = quantity;
	}

	public String getCategory() {
		return Category;
	}

	public void setCategory(String category) {
		Category = category;
	}

	public String getName() {
		return Name;
	}

	public void setName(String name) {
		Name = name;
	}

	public String getTopNutrients() {
		return TopNutrients;
	}

	public void setTopNutrients(String topNutrients) {
		TopNutrients = topNutrients;
	}

	public Integer getDailyPercent() {
		return DailyPercent;
	}

	public void setDailyPercent(Integer dailyPercent) {
		this.DailyPercent = dailyPercent;
	}

	public Integer getCalories() {
		return Calories;
	}

	public void setCalories(Integer calories) {
		Calories = calories;
	}

	public String getQuantity() {
		return Quantity;
	}

	public void setQuantity(String quantity) {
		Quantity = quantity;
	}

}
package demo.grid.grouping_model;

import demo.data.FoodData;

public class FoodGroupViewModel {
	
	private boolean showGroup = true;
	
	public FoodGroupingModel getFoodModel() {
		return new FoodGroupingModel(FoodData.getAllFoods(), new FoodComparator(), this.showGroup);
	}
}
package demo.data;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import demo.data.pojo.Food;
import demo.grid.data_filter.FoodFilter;

public class FoodData {

	private static List<Food> foods = new ArrayList<Food>();
	static {
		foods.add(new Food("Vegetables", "Asparagus", "Vitamin K", 115, 43, "1 cup - 92 grams"));
		foods.add(new Food("Vegetables", "Beets", "Folate", 33, 74, "1 cup - 170 grams"));
		foods.add(new Food("Vegetables", "Bell peppers", "Vitamin C", 291, 24, "1 cup - 92 grams"));
		foods.add(new Food("Vegetables", "Cauliflower", "Vitamin C", 92, 28, "1 cup - 124 grams"));
		foods.add(new Food("Vegetables", "Eggplant", "Dietary Fiber", 10, 27, "1 cup - 99 grams"));
		foods.add(new Food("Vegetables", "Onions", "Chromium", 21, 60, "1 cup - 160 grams"));
		foods.add(new Food("Vegetables", "Potatoes", "Vitamin C", 26, 132, "1 cup - 122 grams"));
		foods.add(new Food("Vegetables", "Spinach", "Vitamin K", 1110, 41, "1 cup - 180 grams"));
		foods.add(new Food("Vegetables", "Tomatoes", "Vitamin C", 57, 37, "1 cup - 180 grams"));
		foods.add(new Food("Seafood", "Salmon", "Tryptophan", 103, 261, "4 oz - 113.4 grams"));
		foods.add(new Food("Seafood", "Shrimp", "Tryptophan", 103, 112, "4 oz - 113.4 grams"));
		foods.add(new Food("Seafood", "Scallops", "Tryptophan", 81, 151, "4 oz - 113.4 grams"));
		foods.add(new Food("Seafood", "Cod", "Tryptophan", 90, 119, "4 oz - 113.4 grams"));
		foods.add(new Food("Fruits", "Apples", "Manganese", 33, 61, "1 cup - 160 grams"));
		foods.add(new Food("Fruits", "Cantaloupe", "Vitamin C", 112, 56, "1 cup - 160 grams"));
		foods.add(new Food("Fruits", "Grapes", "Manganese", 33, 61, "1 cup - 92 grams"));
		foods.add(new Food("Fruits", "Pineapple", "Manganese", 128, 75, "1 cup - 155 grams"));
		foods.add(new Food("Fruits", "Strawberries", "Vitamin C", 24, 48, "1 cup - 150 grams"));
		foods.add(new Food("Fruits", "Watermelon", "Vitamin C", 24, 48, "1 cup - 152 grams"));
		foods.add(new Food("Poultry & Lean Meats", "Beef, lean organic", "Tryptophan", 112, 240, "4 oz - 113.4 grams"));
		foods.add(new Food("Poultry & Lean Meats", "Lamb", "Tryptophan", 109, 229, "4 oz - 113.4 grams"));
		foods.add(new Food("Poultry & Lean Meats", "Chicken", "Tryptophan", 121, 223, "4 oz - 113.4 grams"));
		foods.add(new Food("Poultry & Lean Meats", "Venison ", "Protein", 69, 179, "4 oz - 113.4 grams"));
		foods.add(new Food("Grains", "Corn ", "Vatamin B1", 24, 177, "1 cup - 164 grams"));
		foods.add(new Food("Grains", "Oats ", "Manganese", 69, 147, "1 cup - 234 grams"));
		foods.add(new Food("Grains", "Barley ", "Dietary Fiber", 54, 270, "1 cup - 200 grams"));
	}

	public static List<Food> getAllFoods() {
		return foods;
	}
	public static Object[] getAllFoodsArray() {
		return foods.toArray();
	}

	// This Method only used in "Data Filter" Demo
	public static List<Food> getFilterFoods(FoodFilter foodFilter) {
		List<Food> somefoods = new ArrayList<Food>();
		for (Iterator<Food> i = foods.iterator(); i.hasNext();) {
			Food tmp = i.next();
			if (tmp.getCategory().toLowerCase().indexOf(foodFilter.getCategory()) >= 0 &&
				tmp.getName().toLowerCase().indexOf(foodFilter.getName()) >= 0 &&
				tmp.getTopNutrients().toLowerCase().indexOf(foodFilter.getNutrients()) >= 0) {
				somefoods.add(tmp);
			}
		}
		return somefoods;
	}

	// This Method only used in "Header and footer" Demo
	public static List<Food> getFoodsByCategory(String category) {
		List<Food> somefoods = new ArrayList<Food>();
		for (Iterator<Food> i = foods.iterator(); i.hasNext();) {
			Food tmp = i.next();
			if (tmp.getCategory().equals(category))
				somefoods.add(tmp);
		}
		return somefoods;
	}
}
package demo.grid.grouping_model;

import java.util.Comparator;
import java.util.List;

import org.zkoss.zul.GroupsModelArray;

import demo.data.pojo.Food;

public class FoodGroupingModel extends
		GroupsModelArray<Food, String, String, Object> {

	private static final long serialVersionUID = -461450192489761273L;
	private static final String footerString = "Total %d items";
	
	private boolean showGroup;

	public FoodGroupingModel(List<Food> data, Comparator<Food> cmpr, boolean showGroup) {
		super(data.toArray(new Food[0]), cmpr);
		
		this.showGroup = showGroup;
	}

	@Override
	protected String createGroupHead(Food[] groupdata, int index, int col) {
		String ret = "";
		if (groupdata.length > 0) {
			ret = groupdata[0].getCategory();
		}

		return ret;
	}

	@Override
	protected String createGroupFoot(Food[] groupdata, int index, int col) {
		return String.format(footerString, groupdata.length);
	}

	@Override
	public boolean hasGroupfoot(int groupIndex) {
		boolean retBool = false;
		
		if(showGroup) {
			retBool = super.hasGroupfoot(groupIndex);
		}
		
		return retBool;
	}
	
	
}
package demo.grid.grouping_model;

import java.io.Serializable;
import java.util.Comparator;

import org.zkoss.zul.GroupComparator;

import demo.data.pojo.Food;

public class FoodComparator implements Comparator<Food>, GroupComparator<Food>, Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -5442923541968897269L;

	@Override
	public int compare(Food o1, Food o2) {
		return o1.getCategory().compareTo(o2.getCategory().toString());
	}

	@Override
	public int compareGroup(Food o1, Food o2) {
		if(o1.getCategory().equals(o2.getCategory()))
			return 0;
		else
			return 1;
	}

}