In this part, we will add more fields in our customer window such as Phone Number and DOB. Here I am going to show how we can use jquery to mask the input the fields in ZK.
And also I will show how to show the watermark text for the Date and Phone.
Step 1 :
Before going forward, please download jquery file from this location. Just choose the version you want - uncompressed or minified - and you should be set.
And place that file under the web content folder as shown below. You need to add two jquery files
Step 2:
Now let us two more fields in our customer.java bean file as follows
1: package domain;
2:
3: import java.util.Date;
4:
5: public class Customer implements Cloneable {
6:
7: private String lastName;
8: private String firstName;
9: private String email;
10: private Date dateOfBirth;
11: private String phone;
12:
13: public String getLastName() {
14: return lastName;
15: }
16:
17: public void setLastName(String lastName) {
18: this.lastName = lastName;
19: }
20:
21: public String getFirstName() {
22: return firstName;
23: }
24:
25: public void setFirstName(String firstName) {
26: this.firstName = firstName;
27: }
28:
29: public String getEmail() {
30: return email;
31: }
32:
33: public void setEmail(String email) {
34: this.email = email;
35: }
36:
37:
38:
39: public Date getDateOfBirth() {
40: return dateOfBirth;
41: }
42:
43: public void setDateOfBirth(Date dateOfBirth) {
44: this.dateOfBirth = dateOfBirth;
45: }
46:
47: public String getPhone() {
48: return phone;
49: }
50:
51: public void setPhone(String phone) {
52: this.phone = phone;
53: }
54:
55: public Object clone() throws CloneNotSupportedException {
56: return super.clone();
57: }
58: }
Step 2:
Now let us reference our jquery file in addon file as follows
1: <?xml version="1.0" encoding="UTF-8"?>
2: <language-addon>
3: <addon-name>myaddon</addon-name>
4: <language-name>xul/html</language-name>
5: <stylesheet href="/css/style.css" type="text/css" />
6: <javascript src="/js/jquery.maskedinput-1.3.js" />
7: <javascript src="/js/watermarkinput.js" />
8:
9: <component>
10: <component-name>fbutton</component-name>
11: <extends>button</extends>
12: <property>
13: <property-name>mold</property-name>
14: <property-value>trendy</property-value>
15: </property>
16: <property>
17: <property-name>sclass</property-name>
18: <property-value>mybutton orange small bigrounded</property-value>
19: </property>
20: </component>
21:
22:
23: <component>
24: <component-name>Addbutton</component-name>
25: <extends>button</extends>
26: <property>
27: <property-name>mold</property-name>
28: <property-value>trendy</property-value>
29: </property>
30: <property>
31: <property-name>sclass</property-name>
32: <property-value>mybutton green small bigrounded</property-value>
33: </property>
34: </component>
35:
36:
37: <component>
38: <component-name>GoButton</component-name>
39: <extends>button</extends>
40: <property>
41: <property-name>mold</property-name>
42: <property-value>trendy</property-value>
43: </property>
44: <property>
45: <property-name>sclass</property-name>
46: <property-value>mybutton roundsearch</property-value>
47: </property>
48: </component>
49:
50:
51: <component>
52: <component-name>flabeltitle</component-name>
53: <extends>label</extends>
54: <property>
55: <property-name>sclass</property-name>
56: <property-value>flbltitle</property-value>
57: </property>
58: </component>
59:
60: <component>
61: <component-name>fImageEdit</component-name>
62: <extends>image</extends>
63: <property>
64: <property-name>sclass</property-name>
65: <property-value>fimageedit</property-value>
66: </property>
67: <property>
68: <property-name>tooltiptext</property-name>
69: <property-value>Edit</property-value>
70: </property>
71: </component>
72:
73:
74: <component>
75: <component-name>fImageDelete</component-name>
76: <extends>image</extends>
77: <property>
78: <property-name>sclass</property-name>
79: <property-value>fimageDelete</property-value>
80: </property>
81: <property>
82: <property-name>tooltiptext</property-name>
83: <property-value>Delete</property-value>
84: </property>
85: </component>
86:
87:
88: <component>
89: <component-name>fgrid</component-name>
90: <extends>grid</extends>
91: <property>
92: <property-name>sclass</property-name>
93: <property-value>fgrid</property-value>
94: </property>
95: </component>
96:
97:
98: <component>
99: <component-name>ftextbox</component-name>
100: <extends>textbox</extends>
101: <property>
102: <property-name>sclass</property-name>
103: <property-value>ftextbox</property-value>
104: </property>
105: </component>
106:
107: <component>
108: <component-name>flabel</component-name>
109: <extends>label</extends>
110: <property>
111: <property-name>sclass</property-name>
112: <property-value>flabel</property-value>
113: </property>
114: </component>
115:
116:
117: </language-addon>
Step 3:
For DOB and Phone no, we are not going to use ZK Components. Instead of that we will create our simple component by extending ZK Textbox and then we will apply masking
water mark in that. Here are the two class which is the implementation our own component.
1: package component;
2: import org.zkoss.zul.Textbox;
3:
4: public class Datebox extends Textbox {
5:
6: private static final long serialVersionUID = 1L;
7:
8: public Datebox() {
9:
10: setWidgetListener("onBind", "jq(this).mask('99/99/9999');jq(this).Watermark('mm/dd/yyyy','gray');");
11: }
12:
13: }
1: package component;
2: import org.zkoss.zul.Textbox;
3:
4: public class Phonebox extends Textbox {
5: private static final long serialVersionUID = 1L;
6: public Phonebox() {
7: setWidgetListener("onBind", "jq(this).mask('(999) 999-9999');jq(this).Watermark('(###) ###-####','gray');");
8: }
9: }
Step 4:
Then we need to inform ZK Engine that we are going to use our component in the zul files. This can be done by adding the reference in addon file as follows. Let us give the name
of our component such as myDateBox and myPhoneBox
1: <?xml version="1.0" encoding="UTF-8"?>
2: <language-addon>
3: <addon-name>myaddon</addon-name>
4: <language-name>xul/html</language-name>
5: <stylesheet href="/css/style.css" type="text/css" />
6: <javascript src="/js/jquery.maskedinput-1.3.js" />
7: <javascript src="/js/watermarkinput.js" />
8:
9: <component>
10: <component-name>fbutton</component-name>
11: <extends>button</extends>
12: <property>
13: <property-name>mold</property-name>
14: <property-value>trendy</property-value>
15: </property>
16: <property>
17: <property-name>sclass</property-name>
18: <property-value>mybutton orange small bigrounded</property-value>
19: </property>
20: </component>
21:
22:
23: <component>
24: <component-name>Addbutton</component-name>
25: <extends>button</extends>
26: <property>
27: <property-name>mold</property-name>
28: <property-value>trendy</property-value>
29: </property>
30: <property>
31: <property-name>sclass</property-name>
32: <property-value>mybutton green small bigrounded</property-value>
33: </property>
34: </component>
35:
36:
37: <component>
38: <component-name>GoButton</component-name>
39: <extends>button</extends>
40: <property>
41: <property-name>mold</property-name>
42: <property-value>trendy</property-value>
43: </property>
44: <property>
45: <property-name>sclass</property-name>
46: <property-value>mybutton roundsearch</property-value>
47: </property>
48: </component>
49:
50:
51: <component>
52: <component-name>flabeltitle</component-name>
53: <extends>label</extends>
54: <property>
55: <property-name>sclass</property-name>
56: <property-value>flbltitle</property-value>
57: </property>
58: </component>
59:
60: <component>
61: <component-name>fImageEdit</component-name>
62: <extends>image</extends>
63: <property>
64: <property-name>sclass</property-name>
65: <property-value>fimageedit</property-value>
66: </property>
67: <property>
68: <property-name>tooltiptext</property-name>
69: <property-value>Edit</property-value>
70: </property>
71: </component>
72:
73:
74: <component>
75: <component-name>fImageDelete</component-name>
76: <extends>image</extends>
77: <property>
78: <property-name>sclass</property-name>
79: <property-value>fimageDelete</property-value>
80: </property>
81: <property>
82: <property-name>tooltiptext</property-name>
83: <property-value>Delete</property-value>
84: </property>
85: </component>
86:
87:
88: <component>
89: <component-name>fgrid</component-name>
90: <extends>grid</extends>
91: <property>
92: <property-name>sclass</property-name>
93: <property-value>fgrid</property-value>
94: </property>
95: </component>
96:
97:
98: <component>
99: <component-name>ftextbox</component-name>
100: <extends>textbox</extends>
101: <property>
102: <property-name>sclass</property-name>
103: <property-value>ftextbox</property-value>
104: </property>
105: </component>
106:
107: <component>
108: <component-name>flabel</component-name>
109: <extends>label</extends>
110: <property>
111: <property-name>sclass</property-name>
112: <property-value>flabel</property-value>
113: </property>
114: </component>
115:
116: <component>
117: <component-name>myDateBox</component-name>
118: <component-class>component.Datebox
119: </component-class>
120: <extends>textbox</extends>
121: </component>
122:
123: <component>
124: <component-name>myPhoneBox</component-name>
125: <component-class>component.Phonebox
126: </component-class>
127: <extends>textbox</extends>
128: </component>
129:
130: </language-addon>
Step 5:
We are done. Now we can start using our newly created component. See below
1: <?page title="new page title" contentType="text/html;charset=UTF-8"?>
2: <zk>
3: <window title="Customer CRUD" border="normal" id="CustomerCRUD"
4: width="430px" height="auto" apply="org.zkoss.bind.BindComposer"
5: sclass="mymodal" minimizable="false" mode="modal" maximizable="false"
6: closable="true" position="center"
7: viewModel="@id('vm') @init('appVM.CustomerCRUDVM')">
8: <separator />
9: <flabeltitle value="Customer information" />
10: <separator />
11: <panel width="100%">
12: <panelchildren>
13: <separator />
14: <fgrid width="99.5%">
15: <columns>
16: <column label="" width="150px" />
17: <column label="" />
18: </columns>
19: <rows>
20: <row>
21: <hbox>
22: <flabel value="First Name" />
23: </hbox>
24: <ftextbox name="firstName"
25: readonly="@load(vm.makeAsReadOnly)"
26: value="@bind(vm.selectedCustomer.firstName)" cols="20" />
27: </row>
28: <row>
29: <hbox>
30: <flabel value="Last Name" />
31: </hbox>
32: <ftextbox name="LastName"
33: readonly="@load(vm.makeAsReadOnly)"
34: value="@bind(vm.selectedCustomer.lastName)" cols="20" />
35:
36: </row>
37: <row>
38: <hbox>
39: <flabel value="DOB" />
40: </hbox>
41: <myDateBox name="DOB"
42: readonly="@load(vm.makeAsReadOnly)"
43: value="@bind(vm.selectedCustomer.dateOfBirth)" />
44: </row>
45: <row>
46: <hbox>
47: <flabel value="Phone" />
48: </hbox>
49: <myPhoneBox name="Phone"
50: readonly="@load(vm.makeAsReadOnly)"
51: value="@bind(vm.selectedCustomer.phone)" />
52: </row>
53: <row>
54: <hbox>
55: <flabel value="Email" />
56: </hbox>
57: <ftextbox name="firstName"
58: readonly="@load(vm.makeAsReadOnly)"
59: value="@bind(vm.selectedCustomer.email)" cols="20" />
60: </row>
61:
62: </rows>
63: </fgrid>
64: </panelchildren>
65: </panel>
66: <separator />
67: <div align="center">
68: <fbutton id="submit" label="Submit"
69: onClick="@command('save')" visible="@load(not vm.makeAsReadOnly)" />
70: <fbutton id="cancel"
71: label="@load(vm.makeAsReadOnly ?'Ok':'Cancel')"
72: onClick="@command('closeThis')" />
73: </div>
74: <separator />
75: </window>
76: </zk>
Step 6:
Now let us add the two new fields in the list also as follows
1: <?page title="CustomerList" contentType="text/html;charset=UTF-8"?>
2: <zk>
3:
4:
5:
6: <window title="Customer List" border="normal" id="list"
7: apply="org.zkoss.bind.BindComposer"
8: viewModel="@id('myvm') @init('appVM.CustomerListVM')">
9:
10: <div>
11: <Addbutton label="Add New Customer"
12: onClick="@command('addNewCustomer')" />
13: </div>
14: <separator />
15:
16: <listbox sclass="mylist" id="test"
17: model="@load(myvm.allCustomers)"
18: selectedItem="@bind(myvm.curSelectedCustomer)">
19: <listhead sizable="true">
20: <listheader label="Last Name" width="300px"
21: sort="auto(lastName)" />
22: <listheader label="First Name" width="200px"
23: sort="auto(firstName)" />
24: <listheader label="DOB" width="150px"
25: sort="auto(dateOfBirth)" />
26: <listheader label="Phone" width="150px"
27: sort="auto(phone)" />
28: <listheader label="Email" width="200px"
29: sort="auto(email)" />
30: <listheader label="Action" />
31: </listhead>
32: <template name="model" var="p1">
33: <listitem>
34: <listcell label="@load(p1.lastName)"
35: onClick="@command('openAsReadOnly')" sclass="highlightcell" />
36: <listcell label="@load(p1.firstName)" />
37: <listcell
38: label="@load(p1.dateOfBirth)" />
39: <listcell label="@load(p1.phone)" />
40: <listcell label="@load(p1.email)" />
41: <listcell>
42: <hbox spacing="20px">
43: <fImageEdit
44: onClick="@command('editThisCustomer')" />
45: <fImageDelete
46: onClick="@command('deleteThisCustomer')" />
47: </hbox>
48: </listcell>
49: </listitem>
50: </template>
51: </listbox>
52: </window>
53: </zk>
Step 7:
Now you can run customerlist.zul file and check the output.
Step 8:
There is small issue in using masking and watermask. If we are not entering any characters, then masked characters will be stored in the bean. In order to avoid that, we can write
our own converters as follows
1: package component;
2:
3: import java.text.ParseException;
4: import java.text.SimpleDateFormat;
5: import java.util.Date;
6:
7: import org.zkoss.bind.BindContext;
8: import org.zkoss.bind.Converter;
9: import org.zkoss.zk.ui.Component;
10:
11:
12: @SuppressWarnings("rawtypes")
13: public class MyDateFormatConverter implements Converter {
14: /**
15: * Convert Date to String.
16: *
17: * @param val
18: * date to be converted
19: * @param comp
20: * associated component
21: * @param ctx
22: * bind context for associate Binding and extra parameter (e.g.
23: * format)
24: * @return the converted String
25: */
26:
27: /**
28: * The method coerceToUi() is invoked when loading ViewModel's property to component and its return type should correspond to bound
29: * component attribute's value[1]. The coerceToBean() is invoked when saving. If you only need to one way conversion, you can
30: * leave unused method empty.
31: */
32:
33: private static SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
34:
35: public Object coerceToUi(Object val, Component comp, BindContext ctx) {
36: final Date date = (Date) val;
37: return date == null ? null : sdf.format(date);
38: }
39:
40: /**
41: * Convert String to Date.
42: *
43: * @param val
44: * date in string form
45: * @param comp
46: * associated component
47: * @param ctx
48: * bind context for associate Binding and extra parameter (e.g.
49: * format)
50: * @return the converted Date
51: */
52: public Object coerceToBean(Object val, Component comp, BindContext ctx) {
53: final String date = (String) val;
54: sdf.setLenient(false);
55: try {
56: return date == null ? null : sdf.parse(date);
57: } catch (ParseException e) {
58: comp.invalidate();
59: return null;
60:
61: }
62: }
63:
64: }
1: package component;
2:
3: import org.zkoss.bind.BindContext;
4: import org.zkoss.bind.Converter;
5: import org.zkoss.zk.ui.Component;
6:
7: @SuppressWarnings("rawtypes")
8: public class MyPhoneConverter implements Converter {
9:
10: /**
11: * The method coerceToUi() is invoked when loading ViewModel's property to
12: * component and its return type should correspond to bound component
13: * attribute's value[1]. The coerceToBean() is invoked when saving. If you
14: * only need to one way conversion, you can leave unused method empty.
15: */
16:
17: public Object coerceToUi(Object val, Component comp, BindContext ctx) {
18: // do nothing
19: return val;
20: }
21:
22: public Object coerceToBean(Object val, Component comp, BindContext ctx) {
23: /*
24: * Here we will check only masking characters are present, if so, then
25: * return null
26: */
27: final String propValue = (String) val;
28: if (IsEmptyByMask(propValue))
29: return null;
30: else
31: return val;
32:
33: }
34:
35: public boolean IsEmptyByMask(String s1) {
36: if (isEmpty(s1) == false) {
37: s1 = s1.replaceAll("_", "").replace("(", "").replace(")", "")
38: .replace("-", "").replace(" ", "").replace("/", "").trim();
39: if (isEmpty(s1))
40: return true;
41: else
42: return false;
43: }
44: return true;
45: }
46:
47: public static boolean isEmpty(String s) {
48: return s == null || s.trim().length() == 0;
49: }
50: }
Step 9:
Now let us add the converter both in Listing and CRUD Page as follows
1: <?page title="CustomerList" contentType="text/html;charset=UTF-8"?>
2: <zk>
3:
4:
5:
6: <window title="Customer List" border="normal" id="list"
7: apply="org.zkoss.bind.BindComposer"
8: viewModel="@id('myvm') @init('appVM.CustomerListVM')">
9:
10: <div>
11: <Addbutton label="Add New Customer"
12: onClick="@command('addNewCustomer')" />
13: </div>
14: <separator />
15:
16: <listbox sclass="mylist" id="test"
17: model="@load(myvm.allCustomers)"
18: selectedItem="@bind(myvm.curSelectedCustomer)">
19: <listhead sizable="true">
20: <listheader label="Last Name" width="300px"
21: sort="auto(lastName)" />
22: <listheader label="First Name" width="200px"
23: sort="auto(firstName)" />
24: <listheader label="DOB" width="150px"
25: sort="auto(dateOfBirth)" />
26: <listheader label="Phone" width="150px"
27: sort="auto(phone)" />
28: <listheader label="Email" width="200px"
29: sort="auto(email)" />
30: <listheader label="Action" />
31: </listhead>
32: <template name="model" var="p1">
33: <listitem>
34: <listcell label="@load(p1.lastName)"
35: onClick="@command('openAsReadOnly')" sclass="highlightcell" />
36: <listcell label="@load(p1.firstName)" />
37: <listcell
38: label="@load(p1.dateOfBirth) @converter('component.MyDateFormatConverter')" />
39: <listcell label="@load(p1.phone)" />
40: <listcell label="@load(p1.email)" />
41: <listcell>
42: <hbox spacing="20px">
43: <fImageEdit
44: onClick="@command('editThisCustomer')" />
45: <fImageDelete
46: onClick="@command('deleteThisCustomer')" />
47: </hbox>
48: </listcell>
49: </listitem>
50: </template>
51: </listbox>
52: </window>
53: </zk>
1: <?page title="new page title" contentType="text/html;charset=UTF-8"?>
2: <zk>
3: <window title="Customer CRUD" border="normal" id="CustomerCRUD"
4: width="430px" height="auto" apply="org.zkoss.bind.BindComposer"
5: sclass="mymodal" minimizable="false" mode="modal" maximizable="false"
6: closable="true" position="center"
7: viewModel="@id('vm') @init('appVM.CustomerCRUDVM')">
8: <separator />
9: <flabeltitle value="Customer information" />
10: <separator />
11: <panel width="100%">
12: <panelchildren>
13: <separator />
14: <fgrid width="99.5%">
15: <columns>
16: <column label="" width="150px" />
17: <column label="" />
18: </columns>
19: <rows>
20: <row>
21: <hbox>
22: <flabel value="First Name" />
23: </hbox>
24: <ftextbox name="firstName"
25: readonly="@load(vm.makeAsReadOnly)"
26: value="@bind(vm.selectedCustomer.firstName)" cols="20" />
27: </row>
28: <row>
29: <hbox>
30: <flabel value="Last Name" />
31: </hbox>
32: <ftextbox name="LastName"
33: readonly="@load(vm.makeAsReadOnly)"
34: value="@bind(vm.selectedCustomer.lastName)" cols="20" />
35:
36: </row>
37: <row>
38: <hbox>
39: <flabel value="DOB" />
40: </hbox>
41: <myDateBox name="DOB"
42: readonly="@load(vm.makeAsReadOnly)"
43: value="@bind(vm.selectedCustomer.dateOfBirth) @converter('component.MyDateFormatConverter')" />
44: </row>
45: <row>
46: <hbox>
47: <flabel value="Phone" />
48: </hbox>
49: <myPhoneBox name="Phone"
50: readonly="@load(vm.makeAsReadOnly)"
51: value="@bind(vm.selectedCustomer.phone) @converter('component.MyPhoneConverter')" />
52: </row>
53: <row>
54: <hbox>
55: <flabel value="Email" />
56: </hbox>
57: <ftextbox name="firstName"
58: readonly="@load(vm.makeAsReadOnly)"
59: value="@bind(vm.selectedCustomer.email)" cols="20" />
60: </row>
61:
62: </rows>
63: </fgrid>
64: </panelchildren>
65: </panel>
66: <separator />
67: <div align="center">
68: <fbutton id="submit" label="Submit"
69: onClick="@command('save')" visible="@load(not vm.makeAsReadOnly)" />
70: <fbutton id="cancel"
71: label="@load(vm.makeAsReadOnly ?'Ok':'Cancel')"
72: onClick="@command('closeThis')" />
73: </div>
74: <separator />
75: </window>
76: </zk>
0 comments:
Post a Comment