Processing...
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.


grouping_model_view.zul
<div apply="org.zkoss.bind.BindComposer"
	viewModel="@id('vm') @init('demo.grid.grouping_model.FoodGroupViewModel')">
	<grid id="demoGrid" height="400px"
		model="@load(vm.foodModel)">
		<columns menupopup="auto">
			<column sort="auto(Name)" label="Name" width="150px"/>
			<column sort="auto(TopNutrients)" label="Top Nutrients" hflex="1" /> 
			<column sort="auto(DailyPercent)" label="% of Daily" hflex="1" align="center"/>
			<column sort="auto(Calories)" label="Calories" hflex="1" align="center"  />
			<column sort="auto(Quantity)" label="Quantity" width="120px"/>
		</columns>
		<!-- template for group -->
		<template name="model:group">
			<group label="@load(each)" />
		</template>
		
		<!-- template for each element in model -->
		<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 for footer -->
		<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>
FoodGroupViewModel.java
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);
	}
}
FoodGroupingModel.java
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 = 1L;
	
	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;
	}

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

		return ret;
	}

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

	public boolean hasGroupfoot(int groupIndex) {
		boolean retBool = false;
		
		if(showGroup) {
			retBool = super.hasGroupfoot(groupIndex);
		}
		
		return retBool;
	}
}
FoodComparator.java
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 = 1L;

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

	public int compareGroup(Food o1, Food o2) {
		if(o1.getCategory().equals(o2.getCategory()))
			return 0;
		else
			return 1;
	}
}
FoodData.java
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 new ArrayList<Food>(foods);
	}
	public static Food[] getAllFoodsArray() {
		return foods.toArray(new Food[foods.size()]);
	}

	// This Method only used in "Data Filter" Demo
	public static List<Food> getFilterFoods(FoodFilter foodFilter) {
		List<Food> somefoods = new ArrayList<Food>();
		String cat = foodFilter.getCategory().toLowerCase();
		String nm = foodFilter.getName().toLowerCase();
		String nut = foodFilter.getNutrients().toLowerCase();
		
		for (Iterator<Food> i = foods.iterator(); i.hasNext();) {
			Food tmp = i.next();
			if (tmp.getCategory().toLowerCase().contains(cat) &&
				tmp.getName().toLowerCase().contains(nm)  &&
				tmp.getTopNutrients().toLowerCase().contains(nut)) {
				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().equalsIgnoreCase(category)){
				somefoods.add(tmp);
			}
		}
		return somefoods;
	}
}
Food.java
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) {
		this.category = category;
		this.name = name;
		this.topNutrients = topNutrients;
		this.dailyPercent = dailyPercent;
		this.calories = calories;
		this.quantity = quantity;
	}

	public String getCategory() {
		return category;
	}

	public void setCategory(String category) {
		this.category = category;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getTopNutrients() {
		return topNutrients;
	}

	public void setTopNutrients(String topNutrients) {
		this.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) {
		this.calories = calories;
	}

	public String getQuantity() {
		return quantity;
	}

	public void setQuantity(String quantity) {
		this.quantity = quantity;
	}

}