Chapter 6: Implementing CRUD"
(→Read) |
(→Update) |
||
Line 200: | Line 200: | ||
== Update == | == Update == | ||
+ | |||
+ | To update a to-do item, you should select an item first then detail editor will appear. The following codes demonstrate how to listen a "onSelect" event and display the item's detail. | ||
+ | |||
+ | |||
+ | <source lang='java' high='29'> | ||
+ | public class TodoListController extends SelectorComposer<Component>{ | ||
+ | |||
+ | |||
+ | //wire components | ||
+ | @Wire | ||
+ | Textbox todoSubject; | ||
+ | @Wire | ||
+ | Button addTodo; | ||
+ | @Wire | ||
+ | Listbox todoListbox; | ||
+ | |||
+ | @Wire | ||
+ | Component selectedTodoBlock; | ||
+ | @Wire | ||
+ | Checkbox selectedTodoCheck; | ||
+ | @Wire | ||
+ | Textbox selectedTodoSubject; | ||
+ | @Wire | ||
+ | Radiogroup selectedTodoPriority; | ||
+ | @Wire | ||
+ | Datebox selectedTodoDate; | ||
+ | @Wire | ||
+ | Textbox selectedTodoDescription; | ||
+ | @Wire | ||
+ | Button updateSelectedTodo; | ||
+ | |||
+ | |||
+ | //when user selects a todo of the listbox | ||
+ | @Listen("onSelect = #todoListbox") | ||
+ | public void doTodoSelect() { | ||
+ | if(todoListModel.isSelectionEmpty()){ | ||
+ | //just in case for the no selection | ||
+ | selectedTodo = null; | ||
+ | }else{ | ||
+ | selectedTodo = todoListModel.getSelection().iterator().next(); | ||
+ | } | ||
+ | refreshDetailView(); | ||
+ | } | ||
+ | |||
+ | private void refreshDetailView() { | ||
+ | //refresh the detail view of selected todo | ||
+ | if(selectedTodo==null){ | ||
+ | //clean | ||
+ | selectedTodoBlock.setVisible(false); | ||
+ | selectedTodoCheck.setChecked(false); | ||
+ | selectedTodoSubject.setValue(null); | ||
+ | selectedTodoDate.setValue(null); | ||
+ | selectedTodoDescription.setValue(null); | ||
+ | updateSelectedTodo.setDisabled(true); | ||
+ | |||
+ | priorityListModel.clearSelection(); | ||
+ | }else{ | ||
+ | selectedTodoBlock.setVisible(true); | ||
+ | selectedTodoCheck.setChecked(selectedTodo.isComplete()); | ||
+ | selectedTodoSubject.setValue(selectedTodo.getSubject()); | ||
+ | selectedTodoDate.setValue(selectedTodo.getDate()); | ||
+ | selectedTodoDescription.setValue(selectedTodo.getDescription()); | ||
+ | updateSelectedTodo.setDisabled(false); | ||
+ | |||
+ | priorityListModel.addToSelection(selectedTodo.getPriority()); | ||
+ | } | ||
+ | } | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | </source> | ||
+ | * Line 29: Use <tt>@Listen</tt> to listen <tt>onSelect</tt> event of the ''Listbox'' whose id is <tt>todoListbox</tt>. | ||
+ | * Line 30: This method checks <tt>todoListModel</tt>'s selection and refreshes the detail editor. | ||
+ | * Line 40: If an item is selected, it makes detail editor visible and pushes data into those input components of the editor by calling setter methods. If no item selected, it turns detail editor invisible and clear all input components' value. | ||
== Create == | == Create == |
Revision as of 07:57, 23 January 2013
Target Application
In this chapter, we are going to build an application with 4 basic operations, CRUD (Create, Read, Update, and Delete). The application's user interface looks like the images below:
Select an Item:
It is a personal todo list management system and it has following features:
- List all todo items
- Create a todo item.
- Type item name in upper-left textbox and click File:Tutorial-chi6-plus.png or press "Enter" key to create a new todo item.
- Finish a todo item.
- Click the checkbox in front of a todo item to mark it as finished and the item name will be decorated with line-through.
- Modify a todo item.
- Click an existing item and the detail editor appears. Then you can edit the item's details.
- Delete a todo item.
- Click File:Tutorial-chi6-cross.png to delete an existing todo item.
MVC Approach
If you have read previous chapters, constructing user interface for the example application should not be a big problem. Let's look at the layout first and ignore the details.
Layout in chapter6/todolist-mvc.zul
<?link rel="stylesheet" type="text/css" href="/style.css"?>
<window apply="org.zkoss.tutorial.chapter6.mvc.TodoListController"
border="normal" hflex="1" vflex="1" contentStyle="overflow:auto">
<caption src="/imgs/todo.png" sclass="fn-caption" label="Todo List (MVC)"/>
<borderlayout>
<center autoscroll="true" border="none">
<vlayout hflex="1" vflex="1">
<!-- todo creation function-->
<!-- todo list -->
</vlayout>
</center>
<east id="selectedTodoBlock" visible="false" width="300px" border="none" collapsible="false" splittable="true" minsize="300" autoscroll="true">
<vlayout >
<!-- detail editor -->
</vlayout>
</east>
</borderlayout>
</window>
- Line 5: We construct the user interface with Border Layout to separate layout into 2 areas.
- Line 6: The center area contains a todo creation function and a todo list.
- Line 12: The east area is a todo item editor which is invisible if no item selected.
Read
As we talked in previous chapters, we can use Template to define how to display a data model list with implicit variable each.
Display a To-do List
...
<listbox id="todoListbox" vflex="1">
<listhead>
<listheader width="30px" />
<listheader/>
<listheader hflex="min"/>
</listhead>
<template name="model">
<listitem sclass="${each.complete?'complete-todo':''}" value="${each}">
<listcell>
<checkbox forward="onCheck=todoListbox.onTodoCheck" checked="${each.complete}"/>
</listcell>
<listcell>
<label value="${each.subject}"/>
</listcell>
<listcell>
<button forward="onClick=todoListbox.onTodoDelete" image="/imgs/cross.png" width="36px"/>
</listcell>
</listitem>
</template>
</listbox>
...
- Line 8: The default value for required attribute name is "model".
- Line 9: We can implement simple presentation logic with EL expression. Here we apply different styles according to a flag each.complete. We also set a whole object in value attribute, and later we can get the object in the composer.
- Line 11: The each.complete is a boolean variable so that we can assign it to checked. By doing this, the Checkbox will be checked if the to-do item's compelete variable is true.
- Line 11, 17: The forward attribute is used to forward events to another component and we will talk about it in later sections.
In the composer, we should provide a data model for the Listbox.
public class TodoListController extends SelectorComposer<Component>{
//wire components
...
@Wire
Listbox todoListbox;
...
//services
TodoListService todoListService = new TodoListServiceChapter6Impl();
//data for the view
ListModelList<Todo> todoListModel;
ListModelList<Priority> priorityListModel;
Todo selectedTodo;
@Override
public void doAfterCompose(Component comp) throws Exception{
super.doAfterCompose(comp);
//get data from service and wrap it to list-model for the view
List<Todo> todoList = todoListService.getTodoList();
todoListModel = new ListModelList<Todo>(todoList);
todoListbox.setModel(todoListModel);
...
}
...
}
- Line 25 ~ 27: We initialize the data model in doAfterCompose(). Get data from the service class todoListService and create a ListModelList object. Then set it as the data model of todoListbox.
There is a priority radiogroup in to-do item detail editor appeared on the right hand side when you select an item.
In our application, its priority labels come from a enumeration Priority instead of a static text. We can still use Template to define how to create each Radio under a Radiogroup. The zul looks like as follows:
...
<grid hflex="1">
<columns>
<column align="right" hflex="min"/>
<column/>
</columns>
<rows>
<row>
<cell sclass="row-title">Priority :</cell>
<cell>
<radiogroup id="selectedTodoPriority">
<template name="model">
<radio label="${each.label}"/>
</template>
</radiogroup>
</cell>
</row>
...
- Line 12 ~14: Define how to create each Radio with Template and assign each.label to label attribute.
We also need to provide a data model for the Radiogroup in the composer:
public class TodoListController extends SelectorComposer<Component>{
//wire components
...
@Wire
Listbox todoListbox;
...
@Wire
Radiogroup selectedTodoPriority;
...
//services
TodoListService todoListService = new TodoListServiceChapter6Impl();
//data for the view
ListModelList<Todo> todoListModel;
ListModelList<Priority> priorityListModel;
Todo selectedTodo;
@Override
public void doAfterCompose(Component comp) throws Exception{
super.doAfterCompose(comp);
//get data from service and wrap it to list-model for the view
List<Todo> todoList = todoListService.getTodoList();
todoListModel = new ListModelList<Todo>(todoList);
todoListbox.setModel(todoListModel);
priorityListModel = new ListModelList<Priority>(Priority.values());
selectedTodoPriority.setModel(priorityListModel);
}
...
}
- Line 31, 32: Create a LisModelList with Priority and set it as a model of selectedTodoPriority.
Update
To update a to-do item, you should select an item first then detail editor will appear. The following codes demonstrate how to listen a "onSelect" event and display the item's detail.
public class TodoListController extends SelectorComposer<Component>{
//wire components
@Wire
Textbox todoSubject;
@Wire
Button addTodo;
@Wire
Listbox todoListbox;
@Wire
Component selectedTodoBlock;
@Wire
Checkbox selectedTodoCheck;
@Wire
Textbox selectedTodoSubject;
@Wire
Radiogroup selectedTodoPriority;
@Wire
Datebox selectedTodoDate;
@Wire
Textbox selectedTodoDescription;
@Wire
Button updateSelectedTodo;
//when user selects a todo of the listbox
@Listen("onSelect = #todoListbox")
public void doTodoSelect() {
if(todoListModel.isSelectionEmpty()){
//just in case for the no selection
selectedTodo = null;
}else{
selectedTodo = todoListModel.getSelection().iterator().next();
}
refreshDetailView();
}
private void refreshDetailView() {
//refresh the detail view of selected todo
if(selectedTodo==null){
//clean
selectedTodoBlock.setVisible(false);
selectedTodoCheck.setChecked(false);
selectedTodoSubject.setValue(null);
selectedTodoDate.setValue(null);
selectedTodoDescription.setValue(null);
updateSelectedTodo.setDisabled(true);
priorityListModel.clearSelection();
}else{
selectedTodoBlock.setVisible(true);
selectedTodoCheck.setChecked(selectedTodo.isComplete());
selectedTodoSubject.setValue(selectedTodo.getSubject());
selectedTodoDate.setValue(selectedTodo.getDate());
selectedTodoDescription.setValue(selectedTodo.getDescription());
updateSelectedTodo.setDisabled(false);
priorityListModel.addToSelection(selectedTodo.getPriority());
}
}
...
}
- Line 29: Use @Listen to listen onSelect event of the Listbox whose id is todoListbox.
- Line 30: This method checks todoListModel's selection and refreshes the detail editor.
- Line 40: If an item is selected, it makes detail editor visible and pushes data into those input components of the editor by calling setter methods. If no item selected, it turns detail editor invisible and clear all input components' value.