Column Chooser

From Documentation
Column Chooser

Author
Sam Chuang, Engineer, Potix Corporation
Date
May 30, 2013
Version
ZK 6.5 and later

Under Construction-100x100.png This paragraph is under construction.

Introduction

By default, in a ZK Grid or Listbox, you can click the arrow on the header menu to select the columns to hide or to display. When there are a lot of columns, a Columnchooser can be very convenient for arranging these columns. Columnchooser is a popup component that shows a dialog of columns, grouped by column visibility. Columnchooser's dialog is made of two listbox, and few buttons:

Column Chooser Firstlook Default.png


One advantage of Columnchooser is it's design to works with any tabular components, easily integrate with Grid, Listbox for instance. Another noteable feature of Columnchooser is it's based on ZK MVVM, with it's advantage: developer can easily customize the UI (dialog) without touching ViewModel's code.

Column Chooser Firstlook Custom.png

Operation

Button

OK

The OK button is used to confirm modification change. If user doesn't click OK button, the modification will be lose, revert to previsous status.

Demonstraction:

  • Original view

Column Chooser OK BUTTON 1.png

  • After modification, click OK button to confirm.

Column Chooser OK BUTTON 2.png

  • Result

Column Chooser OK BUTTON 3.png

Cancel

The Cancel button is used to revert to previsous status.

Demonstraction:

  • Original view

Column Chooser Cancel BUTTON 1.png

  • After modification, click Cancel button to revert.

Column Chooser Cancel BUTTON 2.png

  • Result

Column Chooser Cancel BUTTON 3.png

Add to Visible Column

The Add button is used to move selected hidden column to visible column

Demonstraction:

  • Original view

Column Chooser OK BUTTON 1.png

  • Select a column, then click the Add button

Column Chooser Add BUTTON 2.png

  • Click OK button to confirm

Column Chooser Add BUTTON 3.png

  • Result

Column Chooser Add BUTTON 4.png

Remove Visible Column

The Remove button is used to move visible column to hidden column

Demonstraction:

  • Original view

Column Chooser OK BUTTON 1.png

  • Select a visible column, then click the Remove button

Column Chooser Remove BUTTON 2.png

  • Click OK button to confirm

Column Chooser Remove BUTTON 3.png

  • Result

Column Chooser Remove BUTTON 4.png

Move Visible Column Up

The Move Up button is used to change column order, move select column up.

Demonstraction:

  • Original view

Column Chooser OK BUTTON 1.png

  • Select a visible column, then click the Move Up button

Column Chooser MoveUp BUTTON 2.png

  • Click OK button to confirm

Column Chooser MoveUp BUTTON 3.png

  • Result

Column Chooser MoveUp BUTTON 4.png

Move Visible Column Down

The Move Down button is used change column order, move select column down.

Demonstraction:

  • Original view

Column Chooser OK BUTTON 1.png

  • Select a visible column, then click the Move Down button

Column Chooser MoveDown BUTTON 2.png

  • Click OK button to confirm

Column Chooser MoveDown BUTTON 3.png

  • Result

Column Chooser MoveUp BUTTON 4.png

Drag & Drop

Drag Hidden Column to Visible Column

Demonstraction:

  • Original view

Column Chooser OK BUTTON 1.png

  • Drag hidden column, then drop at visible column area

Column Chooser Drag to Visible 2.png

  • Click OK button to confirm

Column Chooser Drag to Visible 3.png

  • Result

Column Chooser Drag to Visible 4.png

Drag Visible Column to Hidden Column

Demonstraction:

  • Original view

Column Chooser OK BUTTON 1.png

  • Drag visible column, then drop at hidden column area

Column Chooser Drag to Hidden 2.png

  • Click OK button to confirm

Column Chooser Drag to Hidden 3.png

  • Result

Column Chooser Drag to Hidden 4.png

Drag Column and Drop on Any Column

Demonstraction:

  • Original view

Column Chooser OK BUTTON 1.png

  • Drag visible column, then drop at Birth column

Column Chooser Drag and Drop 2.png

  • Click OK button to confirm

Column Chooser Drag and Drop 3.png

  • Result

Column Chooser Drag and Drop 4.png

Usage

Visible Columns and Hidden Columns

Invoke Columnchooser.setVisibleColumns(List<String> columns) and Columnchooser.setHiddenColumns(List<String> columns) to setup columns.

ZUL

<columnchooser 
	visibleColumns="@load(vm.visibleColumnLabels)"
	hiddenColumns="@load(vm.hiddenColumnLabels)" />

Java

public ArrayList<String> getVisibleColumnLabels() {
	...
}
	
public ArrayList<String> getHiddenColumnLabels() {
	...
}

Open Dialog

The Columnchooser is a popup component, invoke Columnchooser.open(Component ref, String position) to open dialog.

Event

When user made change and confrimed, Columnchooser will fire ColumnVisibilityChangeEvent event, the name of the event is onColumnVisibilityChange

ZUL

<columnchooser 
	visibleColumns="@load(vm.visibleColumnLabels)"
	hiddenColumns="@load(vm.hiddenColumnLabels)"
	onColumnVisibilityChange="@command('doColumnVisibilityChange', 
		visibleColumns=event.visibleColumns, 
		hiddenColumns=event.hiddenColumns)"></columnchooser>

Java

@Command
public void doColumnVisibilityChange(
		@BindingParam("visibleColumns") List<String> visibleColumns, 
		@BindingParam("hiddenColumns") List<String> hiddenColumns) { 
...
}

Template

Default

The Columnchooser contains a default implementation: columnchooser.zul

<zk xmlns:n="native">
	<vlayout 
		apply="org.zkoss.bind.BindComposer" 
		viewModel="@id('vm') @init('org.zkoss.addon.columnchooser.impl.ColumnchooserViewModel')">
		<n:span>Choose the fields to display.</n:span>
		<hlayout>
			<vlayout>
				Available fields:
				<listbox model="@load(vm.hiddenColumns)" width="150px"
					height="200px" droppable="true" selectedItem="@bind(vm.selectedHiddenColumn)"
					onDrop="@command('dropToHiddenColumns', column=event.dragged.value)">
					...
				</listbox>
			</vlayout>
				...
			<vlayout>
				Displayed Columns:
				<listbox model="@load(vm.visibleColumns)" width="150px"
					height="200px" droppable="true" selectedItem="@bind(vm.selectedVisibleColumn)"
					onDrop="@command('dropToVisibleColumns', column=event.dragged.value)">
					...
				</listbox>
			</vlayout>
		</hlayout>
		<hbox pack="end" width="100%" spacing="5px">
			<button onClick="@command('ok')" label="OK" mold="trendy" width="75px"></button>
			<button onClick="@command('cancel')" label="Cancel" mold="trendy" width="75px"></button>
		</hbox>
	</vlayout>
</zk>

The defualt implementation group columns by column visibility into two listbox.

Custom Template

Config template per instance

Developer can easily change the view by Columnchooser.setTemplate(String uri)

ZUL

<columnchooser template="/customColumnChooser.zul"
	visibleColumns="@load(vm.visibleColumnLabels)" 
	hiddenColumns="@load(vm.hiddenColumnLabels)"
	onColumnVisibilityChange="@command('doColumnVisibilityChange', 
		visibleColumns=event.visibleColumns, 
		hiddenColumns=event.hiddenColumns)"></columnchooser>

customColumnChooser.zul

<zk xmlns:n="native">
	<window apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('org.zkoss.addon.columnchooser.impl.ColumnchooserViewModel')"
		title="Edit Columns" border="normal" mode="highlighted" position="center">
		<vlayout spacing="5px">
			<label>Choose the fields to display.</label>
			<hlayout spacing="10px">
				<vlayout>
					Available fields:
					<listbox model="@load(vm.hiddenColumns)" width="150px"
						height="200px" droppable="true" selectedItem="@bind(vm.selectedHiddenColumn)"
						onDrop="@command('dropToHiddenColumns', column=event.dragged.value)">
						...
					</listbox>
				</vlayout>
					...
				<vlayout>
					Displayed Columns:
					<listbox model="@load(vm.visibleColumns)" width="150px"
						height="200px" droppable="true" selectedItem="@bind(vm.selectedVisibleColumn)"
						onDrop="@command('dropToVisibleColumns', column=event.dragged.value)">
						...
					</listbox>
				</vlayout>
			</hlayout>
			<hbox pack="end" width="100%" spacing="5px">
				<button onClick="@command('ok')" label="OK" mold="trendy" width="75px"></button>
				<button onClick="@command('cancel')" label="Cancel" mold="trendy" width="75px"></button>
			</hbox>
		</vlayout>
	</window>
</zk>
Config template globally

Change the template view globally by using library property org.zkoss.addon.columnchooser.template in zk.xml

	<library-property>
	    <name>org.zkoss.addon.columnchooser.template</name>
	    <value>/customColumnChooser.zul</value>
	</library-property>

View Model

The default template contains a default ColumnchooserViewModel that implements from Columnchooser.ViewModel

Develper can use customize ViewModel base on ColumnchooserViewModel or implements from Columnchooser.ViewModel

Grid with Columnchooser Demo (MVVM)

index.zul

<zk>
	<window apply="org.zkoss.bind.BindComposer" border="normal"
		viewModel="@id('vm') @init('demo.ProfileViewModel')" hflex="1" vflex="1">
		<caption label="Column Chooser">
			<!-- default column chooser -->
			<columnchooser id="columnchooser" 
				visibleColumns="@load(vm.visibleColumnLabels)"
				hiddenColumns="@load(vm.hiddenColumnLabels)"
				onColumnVisibilityChange="@command('doColumnVisibilityChange', 
					visibleColumns=event.visibleColumns, 
					hiddenColumns=event.hiddenColumns)"></columnchooser>
			<combobutton label="Column Chooser"
				onClick="@command('openDefaultColumnChooser', ref=self)">
				<!-- custom column chooser -->
				<columnchooser 
					template="/customColumnChooser.zul"
					visibleColumns="@load(vm.visibleColumnLabels)" 
					hiddenColumns="@load(vm.hiddenColumnLabels)"
					onColumnVisibilityChange="@command('doColumnVisibilityChange', 
						visibleColumns=event.visibleColumns, 
						hiddenColumns=event.hiddenColumns)"></columnchooser>
			</combobutton>
		</caption>
		<grid model="@load(vm.profiles)" height="500px">
			<columns children="@load(vm.visibleColumns)">
				<template name="children" var="columnInfo">
					<column label="@load(columnInfo.label)"></column>
				</template>
			</columns>
			<template name="model" var="profile">
				<row children="@init(vm.visibleColumns) @template(each.templateName)">
					<template name="label" var="columnInfo">
						<label value="@load(profile[columnInfo.value])"></label>
					</template>
					<template name="birth" var="columnInfo">
						<datebox value="@load(profile[columnInfo.value])"
							onChange="@command('setBirth', profile=profile, birth=event.target.value)"></datebox>
					</template>
					<template name="married" var="columnInfo">
						<checkbox checked="@load(profile[columnInfo.value])"
							onCheck="@command('setMarried', profile=profile, married=event.checked)"
							label="Married"></checkbox>
					</template>
					<template name="skills" var="columnInfo">
						<chosenbox model="@load(vm.allSkills)"
							onSelect="@command('setSkills', profile=profile, skills=event.selectedObjects)"
							selectedObjects="@load(profile[columnInfo.value])" hflex="true">
							<template name="model" var="item">
								<label value="@load(item)"></label>
							</template>
						</chosenbox>
					</template>
				</row>
			</template>
		</grid>
	</window>
</zk>
  • Line 7, 8: setup columns
  • Line 16: custom column chooser dialog
  • Line 25 ~ 27: grid headers
  • Line 30, 31, 32, 35, 39, 44: row content

ProfileViewModel.java

public class ProfileViewModel {
	...
	@Wire
	Columnchooser columnchooser;
	
	@Init
	public void init() {
		_columns = new ArrayList<ColumnInfo>();
		_columns.add(new ColumnInfo("name", "Name", true, "label"));
		_columns.add(new ColumnInfo("birth", "Birth", true, "birth"));
		_columns.add(new ColumnInfo("married", "Marital status", false, "married"));
		_columns.add(new ColumnInfo("skills", "Professional Skill", false, "skills"));
		
		_data = provideData();
	}
	
	@AfterCompose
	public void afterCompose(@ContextParam(ContextType.VIEW) Component view) {
		Selectors.wireComponents(view, this, false);
	}
	
	@Command
	public void openDefaultColumnChooser(@BindingParam("ref") Component ref) {
		columnchooser.open(ref, "after_end");
	}
	
	public List<Profile> getProfiles() {
		return _data;
	}
	
	public ArrayList<ColumnInfo> getVisibleColumns() {
		return getColumns(Filter.VISIBLE);
	}
	
	public ArrayList<String> getVisibleColumnLabels() {
		return transform(getVisibleColumns(), Transformer.TO_LABEL);
	}
	
	public ArrayList<ColumnInfo> getHiddenColumns() {
		return getColumns(Filter.HIDDEN);
	}
	
	public ArrayList<String> getHiddenColumnLabels() {
		return transform(getHiddenColumns(), Transformer.TO_LABEL);
	}
	
	@Command
	@NotifyChange({"visibleColumns", "hiddenColumnLabels", 
		"profiles", "visibleColumnLabels", "hiddenColumnLabels"})
	public void doColumnVisibilityChange(@BindingParam("visibleColumns") List<String> visibleColumns, 
		@BindingParam("hiddenColumns") List<String> hiddenColumns) {
		...
	}
	...
}
  • Line 9 ~12: all columns of the grid
  • Line 24: open columnchooser dialog
  • Line 35, 43: column labels
  • Line 50: columnchooser onColumnVisibilityChange event

Listbox with Columnchooser Demo (MVC)

columnchooser-mvc.zul

<zk>
<window title="Columnchooser with MVC" border="normal" apply="demo.ProfileCtrl">
	<button id="button" label="Column Chooser"></button>
	<columnchooser id="columnchooser"></columnchooser>
	<listbox id="listbox">
		<listhead id="listhead">
		</listhead>
	</listbox>
</window>
</zk>

ProfileCtrl.java

public class ProfileCtrl extends SelectorComposer<Component> {
	
	@Wire
	Button button;
	
	@Wire
	Columnchooser columnchooser;
	
	@Wire
	Listbox listbox;
	
	List<Profile> profiles = Profiles.provideData();
	
	List<String> visibleColumns;
	
	List<String> hiddenColumns;
	@Override
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		...
		columnchooser.setVisibleColumns(visibleColumns);
		columnchooser.setHiddenColumns(hiddenColumns);
		...
	}

	@Listen("onClick=#button")
	public void openColumnChooser() {
		columnchooser.open(button, "end_before");
	}
	
	@Listen("onColumnVisibilityChange=#columnchooser")
	public void doColumnVisibilityChange(ColumnVisibilityChangeEvent event) {
		visibleColumns = event.getVisibleColumns();
		hiddenColumns = event.getHiddenColumns();
		
		Listhead listhead = listbox.getListhead();
		listhead.getChildren().clear();
		for (String visibleColumn : visibleColumns) {
			listhead.appendChild(new Listheader(visibleColumn));
		}
		
		listbox.setModel(new ListModelList<Profile>(profiles));
	}
}
  • Line 21, 22: setup visible columns and hidden columns
  • Line 28: open columnchooser dialog
  • Line 31 ~ 34: reset columns
  • Line 36 ~ 40: redraw listbox headers
  • Line 42: redraw listbox

Summary

In this smalltalk I have demonstrated how application developers can easily integrate Columnchooser component with Grid and Listbox or any tabular components. The Columnchooser component is designed for take advantage of ZK MVVM, allow application developers to customize it extremely easily.

Through the coding of columnchooser component, ZK has proven it's amazing flexibility. You can see how easily to create a component base on default components.

Download

You can get the complete source for the example used in this smalltalk from its github


Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.