/* Description: ZK Essentials History: Created by dennis Copyright (C) 2012 Potix Corporation. All Rights Reserved. */ package org.zkoss.essentials.chapter6.mvvm; import java.io.Serializable; import java.util.Arrays; import java.util.List; import java.util.Map; import org.zkoss.bind.BindUtils; import org.zkoss.bind.Form; import org.zkoss.bind.Property; import org.zkoss.bind.ValidationContext; import org.zkoss.bind.Validator; import org.zkoss.bind.annotation.BindingParam; import org.zkoss.bind.annotation.Command; import org.zkoss.bind.annotation.Init; import org.zkoss.bind.annotation.NotifyChange; import org.zkoss.bind.validator.AbstractValidator; import org.zkoss.essentials.chapter6.TodoListServiceChapter6Impl; import org.zkoss.essentials.entity.Priority; import org.zkoss.essentials.entity.Todo; import org.zkoss.essentials.services.TodoListService; import org.zkoss.lang.Strings; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.ListModelList; public class TodoListViewModel implements Serializable{ private static final long serialVersionUID = 1L; //services TodoListService todoListService = new TodoListServiceChapter6Impl(); //data for the view String subject; ListModelList<Todo> todoListModel; Todo selectedTodo; //getter & setter for the binding of the view public ListModelList<Todo> getTodoListModel() { return todoListModel; } public List<Priority> getPriorityList(){ return Arrays.asList(Priority.values()); } public Todo getSelectedTodo() { return selectedTodo; } public void setSelectedTodo(Todo selectedTodo) { this.selectedTodo = selectedTodo; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } @Init // @Init annotates a initial method public void init(){ //get data from service and wrap it to model for the view List<Todo> todoList = todoListService.getTodoList(); //you can use List directly, however use ListModelList provide efficient control in MVVM todoListModel = new ListModelList<Todo>(todoList); } @Command //@Command annotates a command method @NotifyChange({"selectedTodo","subject"}) //@NotifyChange annotates data changed notification after calling this method public void addTodo(){ if(Strings.isBlank(subject)){ Clients.showNotification("Subject is blank, nothing to do ?"); }else{ //save data selectedTodo = todoListService.saveTodo(new Todo(subject)); //update the model, by using ListModelList, you don't need to notify todoListModel change //it is efficient that only update one item of the listbox todoListModel.add(selectedTodo); todoListModel.addToSelection(selectedTodo); //reset value for fast typing. subject = null; } } @Command //@NotifyChange("selectedTodo") //use postNotifyChange() to notify dynamically public void completeTodo(@BindingParam("todo") Todo todo){ //save data todo = todoListService.updateTodo(todo); if(todo.equals(selectedTodo)){ selectedTodo = todo; //for the case that notification is decided dynamically //you can use BindUtils.postNotifyChange to notify a value changed BindUtils.postNotifyChange(null, null, this, "selectedTodo"); } } @Command //@NotifyChange("selectedTodo") //use postNotifyChange() to notify dynamically public void deleteTodo(@BindingParam("todo") Todo todo){ //save data todoListService.deleteTodo(todo); //update the model, by using ListModelList, you don't need to notify todoListModel change todoListModel.remove(todo); if(todo.equals(selectedTodo)){ //refresh selected todo view selectedTodo = null; //for the case that notification is decided dynamically BindUtils.postNotifyChange(null, null, this, "selectedTodo"); } } @Command @NotifyChange("selectedTodo") public void updateTodo(){ //update data selectedTodo = todoListService.updateTodo(selectedTodo); //update the model, by using ListModelList, you don't need to notify todoListModel change //by reseting an item , it make listbox only refresh one item todoListModel.set(todoListModel.indexOf(selectedTodo), selectedTodo); } //when user clicks the update button @Command @NotifyChange("selectedTodo") public void reloadTodo(){ //do nothing, the selectedTodo will reload by notify change } //the validator is the class to validate data before set ui data back to todo public Validator getTodoValidator(){ return new AbstractValidator() { public void validate(ValidationContext ctx) { //get the form that will be applied to todo Form fx = (Form)ctx.getProperty().getValue(); //get filed subject of the form String subject = (String)fx.getField("subject"); if(Strings.isBlank(subject)){ Clients.showNotification("Subject is blank, nothing to do ?"); //mark the validation is invalid, so the data will not update to bean //and the further command will be skipped. ctx.setInvalid(); } } }; } }