Monday, 4 February 2013

Move List box item up and Down using MVC Design Pattern

Let us see how we can implement Moving the list box item up and down. In almost all the application, we need to change the order of the record that are displayed in the list. Say for an example, if you are defining questions for the subject/exam, then question order is very important. So this example shows how you can change the order of the question using up and down button.

Technologies Used

1. ZK 6.5 CE Version
 

Reference

Project Name and Structure

MVCListBoxMoveUpDown

image

Concepts used in this example

  1. We have used List box to display two column listing.
  2. We also used the "emptyMessage" attribute is used to show a message when listbox contains no items.
  3. In ZK, the controller is responsible for controlling ZK components and listening to events triggered by user interaction.
    We can create a such controller class by simply extending org.zkoss.zk.SelectorComposer.
  4. We also used Annotation in the composer using ZK Select Composer.
  5. MVC Developer reference
  6. We are using Listbox Template concept to display the data.

Step 1:

If you are new ZK, then you can setup the Development environment by downloading this document.

Step 2:

Let us create the Project in eclipse. Click File -> New -> ZK Project . Let us name the project as MVCListBoxMoveUpDown.

Step 3:

Now let us add the domain class Questions.java as follows. Note: We will create a package called "zkmvc" and then we will  create our class "Questions" in that.
package zkmvc;
 
public class Questions {
 
    private Integer questionOrder;
    private String questionName;
 
    public Questions() {
    }
 
    public Questions(Integer questionOrder, String questionName) {
        this.questionOrder = questionOrder;
        this.questionName = questionName;
    }
 
    public Integer getQuestionOrder() {
        return questionOrder;
    }
 
    public void setQuestionOrder(Integer questionOrder) {
        this.questionOrder = questionOrder;
    }
 
    public String getQuestionName() {
        return questionName;
    }
 
    public void setQuestionName(String questionName) {
        this.questionName = questionName;
    }
 
}

Step 4:

We then define a service class to perform the business logic (QuestionService.java) shown below:.

package zkmvc;
 
import java.util.List;
 
public interface QuestionService {
 
    /**
     * Retrieve all questions in the catalog.
     * 
     * @return all questions
     */
    public List<Questions> findAll();
 
}

Step 5:

Next we create our implementation class for the above interface. For simplicity, it uses a static list object as the data model.

package zkmvc;
 
import java.util.LinkedList;
import java.util.List;
 
import org.zkoss.zul.Messagebox;
 
public class QuestionsServiceImpl implements QuestionService {
 
    // data model
    private List<Questions> questionsList = new LinkedList<Questions>();
    private static int id = 1;
 
    // initialize book data
    public QuestionsServiceImpl() {
        questionsList.add(new Questions(1, "What was your childhood nickname?"));
        questionsList.add(new Questions(2, "In what city did you meet your spouse/significant other?"));
        questionsList.add(new Questions(3, "What is the middle name of your oldest child?"));
        questionsList.add(new Questions(4, "What is the name of the place your wedding reception was held?"));
        questionsList.add(new Questions(5, "What year did you graduate from High School?"));
        questionsList.add(new Questions(6, "What was the make and model of your first car?"));
        questionsList.add(new Questions(7, "What is the name of the company of your first job?"));
        
    }
 
    public List<Questions> findAll() {
         
        return questionsList;
    }
 
}

Step 6:

Now we will add our listing zul file as follows

<window title="Questions List" border="normal"
    apply="zkmvc.QuestionsListController">
    <hlayout  >
        <listbox id="questionListbox" width="1000px"
            emptyMessage="No Question found in the result">
            <listhead>
                <listheader label="Question Order" width="20%" />
                <listheader label="Question"  width="80%"/>
            </listhead>
            <template name="model">
                <listitem>
                    <listcell label="${each.questionOrder}"></listcell>
                    <listcell label="${each.questionName}"></listcell>
                </listitem>
            </template>
        </listbox>
        <vbox  >
            <image style="cursor:pointer" id="upBtn"
                src="${imgPath}/uparrow_g.png" />
            <image style="cursor:pointer" id="downBtn"
                src="${imgPath}/downarrow_g.png" />
        </vbox>
    </hlayout>
</window>

Step 7:

Next we will add our MVC Controller for the above zul file which will take of Move up and Move down.

package zkmvc;
 
import java.util.List;
import java.util.Set;
 
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.AbstractListModel;
import org.zkoss.zul.ListModelList;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Messagebox;
 
/**
 * To simplify the implementation of the controller part of UI, ZK provides
 * several skeleton implementations. For example, SelectorComposer, as one of
 * the most popular skeletons, wires components, variables and event listeners
 * automatically based on Java annotations you specify.
 */
public class QuestionsListController extends SelectorComposer<Component> {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * In SelectorComposer, when you specify a @Wire annotation on a field or
     * setter method, the SelectorComposer will automatically find the component
     * and assign it to the field or pass it into the setter method.
     **/
    @Wire
    private Listbox questionListbox;
    private ListModelList<Questions> questionList;
 
    private QuestionService questionService = new QuestionsServiceImpl();
 
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        List<Questions> result = questionService.findAll();
        questionList = new ListModelList<Questions>(result);
        questionListbox.setModel(questionList);
    }
 
    @Listen("onClick = #downBtn")
    public void down() {
 
        int selectedOrder;
        int nextOrder;
 
        Set<Questions> selected = questionList.getSelection();
        //If no item is selected, then do nothing
        if (selected.isEmpty())
            return;
 
        //If selected item is in the last i.e index is eq to size of the list, then do nothing
        int index = questionList.indexOf(selected.iterator().next());
        if (index == questionList.size() - 1 || index < 0)
            return;
 
        //Store the currently selected item
        Questions selectedItem = questionList.get(index);
        
        //Take the next item
        Questions nextItem = questionList.get(index + 1);
        
        //Get the order for the currrently selected Item
        selectedOrder = selectedItem.getQuestionOrder();
        
        //Get the order for the next item of the selected item
        nextOrder = nextItem.getQuestionOrder();
        
        //Swap the order - In the real world, you can make a DB Call to do this
        selectedItem.setQuestionOrder(nextOrder);
        nextItem.setQuestionOrder(selectedOrder);
        
        //Since we changed the order of the next item, we need to refresh the ZUL
        questionList.set(questionList.indexOf(nextItem), nextItem);
 
        //Remove the selected item from the list 
        questionList.remove(selectedItem);
        
        // Add the selected item to the list in the next idex position
        questionList.add(++index, selectedItem);
        
        // Very Important, select the same item once we move down
        questionList.addToSelection(selectedItem);
 
    }
 
    @Listen("onClick = #upBtn")
    public void up() {
 
        int selectedOrder;
        int nextOrder;
 
        Set<Questions> selected = questionList.getSelection();
        if (selected.isEmpty())
            return;
        int index = questionList.indexOf(selected.iterator().next());
        if (index == 0 || index < 0)
            return;
 
        Questions selectedItem = questionList.get(index);
        Questions nextItem = questionList.get(index - 1);
        selectedOrder = selectedItem.getQuestionOrder();
        nextOrder = nextItem.getQuestionOrder();
        selectedItem.setQuestionOrder(nextOrder);
        nextItem.setQuestionOrder(selectedOrder);
        questionList.set(questionList.indexOf(nextItem), nextItem);
 
        questionList.remove(selectedItem);
        questionList.add(--index, selectedItem);
        questionList.addToSelection(selectedItem);
 
    }
 
}

Step 8:

Now you can run the QuestionsList.zul.

image


You can download the source here

2 comments:

  1. Hi Senthil,

    i have problem, to implement in zul part,
    -------------------------------------------
    [code](model:SitacPlan.java)

    public class SitacPlan {

    private LocInfo locInfo;
    private Integer services;
    private Integer imb;
    ...
    ...
    -------------------------------------------
    [code](model:LocInfo.java)

    public class LocInfo{

    private String locId;
    private Integer locServices;
    private Integer locName;
    ...
    ...
    -------------------------------------------
    [code](zul-file)





    -----------------------------------------------------

    the Error :
    org.hibernate.LazyInitializationException: could not initialize proxy - no Session

    any suggestion ?
    thanks

    ReplyDelete
  2. [code](zul-file)
    -----------------
    listitem self="@{each='sitacPlan', init='sitacPlan'}" value="@{sitacPlan}"

    listcell label="@{sitacPlan.locInfo.locName}"
    listcell label="@{sitacPlan.services}"
    listcell label="@{sitacPlan.imb}"
    ___________________________________________________

    ReplyDelete