Advanced Usage of Fragment Component"
m (correct highlight (via JWB)) |
|||
(18 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
− | |||
− | |||
{{Template:Smalltalk_Author| | {{Template:Smalltalk_Author| | ||
|author= Rudy Huang, Engineer, Potix Corporation | |author= Rudy Huang, Engineer, Potix Corporation | ||
− | |date= | + | |date= July 18, 2017 |
|version= ZK 8.5 | |version= ZK 8.5 | ||
}} | }} | ||
Line 14: | Line 12: | ||
== Property Binding and Validation == | == Property Binding and Validation == | ||
− | You can append <code>@validator</code> annotation when you map view model properties onto | + | You can append <code>@validator</code> annotation when you map view model properties onto Fragment properties. It helps you to validate data before saving to the view model. If validation fails, the save process will be aborted and the data will stay unchanged. |
− | <source lang='xml' | + | <source lang='xml' highlight='2'> |
<fragment viewModel="..." | <fragment viewModel="..." | ||
prop1="@bind(vm.prop1) @validator(vm.validator1)"> | prop1="@bind(vm.prop1) @validator(vm.validator1)"> | ||
Line 24: | Line 22: | ||
* Line 2: Append a <code>@validator</code> after <code>@bind</code> annotation to apply a validator. | * Line 2: Append a <code>@validator</code> after <code>@bind</code> annotation to apply a validator. | ||
− | You can retrieve validation messages and display them. All you need to do is define a new property of a | + | You can retrieve validation messages and display them. All you need to do is define a new property of a Fragment using <code>@bind</code> to map the invalid message, so it can be bound by HTML elements. |
− | <source lang='xml' | + | <source lang='xml' highlight='1,3,5'> |
<fragment viewModel="..." validationMessages="@id('vmsgs')" | <fragment viewModel="..." validationMessages="@id('vmsgs')" | ||
prop1="@bind(vm.prop1) @validator(vm.validator1)" | prop1="@bind(vm.prop1) @validator(vm.validator1)" | ||
Line 41: | Line 39: | ||
You can get the invalid message by assigning a self-defined key as an alias. The following is an example code showing how to add an invalid message with a self-defined key in a validator. | You can get the invalid message by assigning a self-defined key as an alias. The following is an example code showing how to add an invalid message with a self-defined key in a validator. | ||
− | <source lang='java' | + | <source lang='java' highlight='4,7'> |
public class RegExValidator extends AbstractValidator { | public class RegExValidator extends AbstractValidator { | ||
public void validate(ValidationContext ctx) { | public void validate(ValidationContext ctx) { | ||
Line 58: | Line 56: | ||
Then we can use it just like this following example. | Then we can use it just like this following example. | ||
− | <source lang='xml' | + | <source lang='xml' highlight='2'> |
<fragment viewModel="..." validationMessages="@id('vmsgs')" | <fragment viewModel="..." validationMessages="@id('vmsgs')" | ||
prop1="@bind(vm.prop1) @validator(vm.regExValidator, key='prop1', regex='^\\d+$')" | prop1="@bind(vm.prop1) @validator(vm.regExValidator, key='prop1', regex='^\\d+$')" | ||
Line 69: | Line 67: | ||
== Form Binding and Validation == | == Form Binding and Validation == | ||
− | You can use [http://books.zkoss.org/zk-mvvm-book/8.0/data_binding/form_binding.html Form Binding] and form validators to validate all fields once and for all. | + | You can use [http://books.zkoss.org/zk-mvvm-book/8.0/data_binding/form_binding.html Form Binding] and form validators to validate all fields once and for all. In the following example code, a form validator is added and the Fragment component will show the invalid messages if any. |
− | <source lang='xml' | + | <source lang='xml' highlight='2,3'> |
<fragment viewModel="..." validationMessages="@id('vmsgs')" | <fragment viewModel="..." validationMessages="@id('vmsgs')" | ||
form="@id('fx') @load(vm) @save(vm, before='submit') @validator(vm.formValidator)" | form="@id('fx') @load(vm) @save(vm, before='submit') @validator(vm.formValidator)" | ||
Line 96: | Line 94: | ||
'''JavaBean''' | '''JavaBean''' | ||
− | <source lang='java' | + | <source lang='java' highlight='4'> |
public class SomeBean { | public class SomeBean { | ||
private String prop1; | private String prop1; | ||
Line 112: | Line 110: | ||
'''ZUML''' | '''ZUML''' | ||
− | <source lang='xml' | + | <source lang='xml' highlight='3'> |
<!-- property binding validation --> | <!-- property binding validation --> | ||
<fragment viewModel="..." validationMessages="@id('vmsgs')" | <fragment viewModel="..." validationMessages="@id('vmsgs')" | ||
Line 123: | Line 121: | ||
* Line 3: Use the predefined <code>beanValidator</code> to validate property <code>prop1</code>. We can assign a custom message key by using key argument. | * Line 3: Use the predefined <code>beanValidator</code> to validate property <code>prop1</code>. We can assign a custom message key by using key argument. | ||
− | <source lang='xml' | + | <source lang='xml' highlight='3'> |
<!-- form binding validation --> | <!-- form binding validation --> | ||
<fragment viewModel="..." validationMessages="@id('vmsgs')" | <fragment viewModel="..." validationMessages="@id('vmsgs')" | ||
Line 137: | Line 135: | ||
== Client-Side Property Validation == | == Client-Side Property Validation == | ||
− | The | + | The Fragment component provides a novel validator called <code>@jsvalidator</code> running at client side, accepting custom JavaScript functions for validation. The benefit is that there is no need to send requests to the server for each validation. However, since the validation logic will be exposed at client side, some simple check, such as empty checking or range checking, is recommended. The usage is like <code>@validator</code> but it is effective only on applying to HTML elements. The text inside the parentheses is the name of the mentioned validation function. Two parameters are passed to the validation function. One is the user input, and the other is a validation message holder object. The validation function is expected to return a Boolean value to tell the component if the data is valid. Only the valid data will be sent to the server for further operations. |
− | <source lang='xml' | + | <source lang='xml' highlight='2,5,6,7,8,9'> |
<fragment viewModel="..." prop1="@bind(vm.prop1)"><![CDATA[ | <fragment viewModel="..." prop1="@bind(vm.prop1)"><![CDATA[ | ||
<input type="text" value="@bind(prop1) @jsvalidator('validation')"/> | <input type="text" value="@bind(prop1) @jsvalidator('validation')"/> | ||
Line 157: | Line 155: | ||
</source> | </source> | ||
* Line 2: Apply <code>@jsvalidator</code> directly to HTML elements. And use the declared <code>validation</code> function as a validation function. | * Line 2: Apply <code>@jsvalidator</code> directly to HTML elements. And use the declared <code>validation</code> function as a validation function. | ||
− | * Line 5-9: The <code>validation</code> function declared here. The logic is very simple. | + | * Line 5-9: The <code>validation</code> function is declared here. The logic is very simple. |
=== The Differences Between @validator and @jsvalidator === | === The Differences Between @validator and @jsvalidator === | ||
Line 179: | Line 177: | ||
|} | |} | ||
</div> | </div> | ||
− | # <code>@validator</code> relies on the server, <code>@jsvalidator</code> relies on the browser. | + | # <code>@validator</code> relies on the server, while <code>@jsvalidator</code> relies on the browser. |
− | # <code>@jsvalidator</code> | + | # <code>@jsvalidator</code> does not support form validation. |
# The validation message holders are not the same. See the following section to know more. | # The validation message holders are not the same. See the following section to know more. | ||
− | For security concerns, we | + | For security concerns, we recommend you to use <code>@validator</code> in most cases and choose <code>@jsvalidator</code> if the validation needs an instant feedback such as password strength. |
=== Validation Message Holder on Client-Side === | === Validation Message Holder on Client-Side === | ||
− | The <code>@jsvalidator</code> also supports validation messages. | + | The <code>@jsvalidator</code> also supports validation messages. There is a predefined message holder object named <code>vmsgs</code> in each Fragment component. This object accepts self-defined keys to get messages. You can retrieve the object from the second argument of a validation function; depending on the validation result you can fill out or clear messages. |
− | You can use an implicit object (<code>vmsgs</code>) to get the client-side invalid message so you | + | You can use an implicit object (<code>vmsgs</code>) to get the client-side invalid message; so you do not need to initialize a validationMessages holder object at the Fragment tag nor bind the invalid messages beforehand. Please note that the holder object is not shared with server side. |
− | <source lang='xml' | + | <source lang='xml' highlight='3'> |
<fragment viewModel="..." prop1="@bind(vm.prop1)"><![CDATA[ | <fragment viewModel="..." prop1="@bind(vm.prop1)"><![CDATA[ | ||
// omitted | // omitted | ||
Line 200: | Line 198: | ||
= Event Handling = | = Event Handling = | ||
− | You can attach DOM events on HTML elements to trigger commands of view models. The command of ViewModel will be executed and receive corresponding event | + | You can attach DOM events on HTML elements to trigger commands of view models. The command of ViewModel will be executed and receive the corresponding event object. |
Following is a quick lookup table of the relation between supported DOM events and ZK Event objects. | Following is a quick lookup table of the relation between supported DOM events and ZK Event objects. | ||
− | {| border="2 | + | {| border="2" |
! ZK Event object | ! ZK Event object | ||
! DOM event | ! DOM event | ||
|- | |- | ||
− | | rowspan="10" | MouseEvent | + | | rowspan="10" | <javadoc>org.zkoss.zk.ui.event.MouseEvent</javadoc> |
| onclick | | onclick | ||
|- | |- | ||
Line 228: | Line 226: | ||
| ondrag | | ondrag | ||
|- | |- | ||
− | | rowspan="3" | KeyEvent | + | | rowspan="3" | <javadoc>org.zkoss.zk.ui.event.KeyEvent</javadoc> |
| onkeydown | | onkeydown | ||
|- | |- | ||
Line 235: | Line 233: | ||
| onkeyup | | onkeyup | ||
|- | |- | ||
− | | rowspan="2" | InputEvent | + | | rowspan="2" | <javadoc>org.zkoss.zk.ui.event.InputEvent</javadoc> |
| onchange | | onchange | ||
|- | |- | ||
| oninput | | oninput | ||
|- | |- | ||
− | | rowspan="2" | CheckEvent | + | | rowspan="2" | <javadoc>org.zkoss.zk.ui.event.CheckEvent</javadoc> |
| onchange (checkbox) | | onchange (checkbox) | ||
|- | |- | ||
| oninput (checkbox) | | oninput (checkbox) | ||
|- | |- | ||
− | | SelectionEvent | + | | <javadoc>org.zkoss.zk.ui.event.SelectionEvent</javadoc> |
| onselect | | onselect | ||
|- | |- | ||
− | | DropEvent | + | | <javadoc>org.zkoss.zk.ui.event.DropEvent</javadoc> |
| ondrop | | ondrop | ||
|- | |- | ||
− | | rowspan="4" | Event | + | | rowspan="4" | <javadoc>org.zkoss.zk.ui.event.Event</javadoc> |
| onblur | | onblur | ||
|- | |- | ||
Line 261: | Line 259: | ||
|} | |} | ||
− | To retrieve an event object, use a reserved keyword "event" in arguments of <code>@command</code> or apply annotation <code>@ContextParam(ContextType.TRIGGER_EVENT)</code> on a parameter of the command method. | + | To retrieve an event object, use a reserved keyword "<code>event</code>" in arguments of <code>@command</code> or apply annotation <code>@ContextParam(ContextType.TRIGGER_EVENT)</code> on a parameter of the command method. For further information, check [http://books.zkoss.org/zk-mvvm-book/8.0/advanced/parameters.html#retrieve-event-object Retrieve Event Object]. For properties of each event object, find out at: [https://www.zkoss.org/javadoc/latest/zk/org/zkoss/zk/ui/event/package-frame.html org.zkoss.zk.ui.event Javadoc]. |
+ | |||
+ | <source lang='xml' highlight='2'> | ||
+ | <fragment viewModel="..."><![CDATA[ | ||
+ | <button onclick="@command('cmd1', e=event)">Hit me!</button> | ||
+ | <input type="checkbox" onchange="@command('cmd2')"/> | ||
+ | ]]></fragment> | ||
+ | </source> | ||
+ | * Line 2: Use a reserved keyword "<code>event</code>" in arguments. | ||
+ | |||
+ | <source lang='java' highlight='4,11'> | ||
+ | public class EventVM { | ||
+ | // Method 1 | ||
+ | @Command | ||
+ | public void cmd1(@BindingParam("e") MouseEvent e) { | ||
+ | // do something with event | ||
+ | // omitted | ||
+ | } | ||
+ | |||
+ | // Method 2 | ||
+ | @Command | ||
+ | public void cmd2(@ContextParam(ContextType.TRIGGER_EVENT) CheckEvent e) { | ||
+ | // do something with event | ||
+ | // omitted | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | * Line 4: Retrieve the binding parameter <code>e</code> as an event object. | ||
+ | * Line 11: Apply a <code>@ContextParam</code> annotation to retrieve the triggering event object. | ||
= Summary = | = Summary = | ||
− | In this article, we | + | In this article, we show the interaction between Fragment component and ZK MVVM mechanism. You can validate native HTML elements by using <code>@validator</code>, applying form binding, using built-in JSR 303 bean validators or trying a client-side <code>@jsvalidator</code>. You can display the invalid messages after each validation. |
+ | |||
+ | In the second part we describe the event object of the relative DOM events. You can get more details from the event object such as mouse cursor position, pressed keys, entered text, and selected text. | ||
− | + | The complete demo source code is available on <span class="galink">[https://github.com/zkoss-demo/zkfragment-demo-part2 GitHub]</span>. | |
− | |||
= References = | = References = |
Latest revision as of 04:30, 20 January 2022
Rudy Huang, Engineer, Potix Corporation
July 18, 2017
ZK 8.5
Introduction
The previous blog post "Client Binding with ZK MVVM for your eyes only" gives you a brief introduction on Fragment component in the upcoming ZK 8.5. This article will further explain advanced usage of this component, especially about data validation and event handling.
Data Validation
To ensure data is correct and useful, we can leverage validators. Fragment component supports property binding validation, form binding validation and client-side property validation. Client-side property validation is only available in this component. This section will explain them one by one.
Property Binding and Validation
You can append @validator
annotation when you map view model properties onto Fragment properties. It helps you to validate data before saving to the view model. If validation fails, the save process will be aborted and the data will stay unchanged.
<fragment viewModel="..."
prop1="@bind(vm.prop1) @validator(vm.validator1)">
// omitted
</fragment>
- Line 2: Append a
@validator
after@bind
annotation to apply a validator.
You can retrieve validation messages and display them. All you need to do is define a new property of a Fragment using @bind
to map the invalid message, so it can be bound by HTML elements.
<fragment viewModel="..." validationMessages="@id('vmsgs')"
prop1="@bind(vm.prop1) @validator(vm.validator1)"
prop1err="@bind(vmsgs['prop1'])"><![CDATA[
<input type="text" value="@bind(prop1)"/>
<span textContent="@load(prop1err)"/>
]]></fragment>
- Line 1: Don't forget to initialize a validation message holder.
- Line 3: Bind an invalid message to prop1err.
- Line 5: Use
@load
to get the invalid message.
Self-Defined Message Keys
You can get the invalid message by assigning a self-defined key as an alias. The following is an example code showing how to add an invalid message with a self-defined key in a validator.
public class RegExValidator extends AbstractValidator {
public void validate(ValidationContext ctx) {
String regex = (String) ctx.getValidatorArg("regex");
String key = (String) ctx.getValidatorArg("key");
Object value = ctx.getProperty().getValue();
if (value == null || !value.toString().matches(regex)) {
addInvalidMessage(ctx, key, "Invalid: " + value);
}
}
}
- Line 4: Get a key from the arguments of a validator.
- Line 7: Use
addInvalidMessage(ValidationContext ctx, String key, String message)
to add a message with a key.
Then we can use it just like this following example.
<fragment viewModel="..." validationMessages="@id('vmsgs')"
prop1="@bind(vm.prop1) @validator(vm.regExValidator, key='prop1', regex='^\\d+$')"
prop1err="@bind(vmsgs['prop1'])">
<input type="text" value="@bind(prop1)"/>
<span textContent="@load(prop1err)"/>
</fragment>
- Line 2: Pass arguments (key, regex) to the validator.
Form Binding and Validation
You can use Form Binding and form validators to validate all fields once and for all. In the following example code, a form validator is added and the Fragment component will show the invalid messages if any.
<fragment viewModel="..." validationMessages="@id('vmsgs')"
form="@id('fx') @load(vm) @save(vm, before='submit') @validator(vm.formValidator)"
prop1="@bind(fx.prop1)" prop1err="@bind(vmsgs['fkey1'])"
prop2="@bind(fx.prop2)" prop2err="@bind(vmsgs['fkey2'])"><![CDATA[
<p><input type="text" value="@bind(prop1)"/><span textContent="@load(prop1err)"/></p>
<p><input type="text" value="@bind(prop2)"/><span textContent="@load(prop2err)"/></p>
<button onclick="@command('submit')">Submit</button>
]]></fragment>
- Line 2: Apply form binding by assigning form property to a component.
- Line 3: Use the form middle object
fx
instead of ViewModel.
JSR 303 Bean Validation
ZK provides built-in validators. Both BeanValidator and FormBeanValidator integrate the Bean Validation 1.0 (JSR 303). For the introduction and environment setup please find the ZK MVVM Book: Using a Built-in Validator. The following example code uses beanValidator and formBeanValidator to validate a JavaBean that is annotated with some constraints.
ViewModel
public class DemoVM {
private SomeBean someBean = new SomeBean();
// getter and setter are omitted
}
JavaBean
public class SomeBean {
private String prop1;
@Size(min = 3, message = "The prop1 is too short (minimum is 3 characters)")
public String getProp1() {
return this.prop1;
}
public void setProp1(String prop1) {
this.prop1 = prop1;
}
}
- Line 4: Use annotations that JSR 303 provided to define a constraint.
ZUML
<!-- property binding validation -->
<fragment viewModel="..." validationMessages="@id('vmsgs')"
prop1="@bind(vm.someBean.prop1) @validator('beanValidator', key='fkey1')"
prop1err="@bind(vmsgs['fkey1'])"><![CDATA[
<input type="text" value="@bind(prop1)"/>
<span textContent="@load(prop1err)"/>
]]></fragment>
- Line 3: Use the predefined
beanValidator
to validate propertyprop1
. We can assign a custom message key by using key argument.
<!-- form binding validation -->
<fragment viewModel="..." validationMessages="@id('vmsgs')"
form="@id('fx') @load(vm.someBean) @save(vm.someBean, before='submit') @validator('formBeanValidator', prefix='p_')"
prop1="@bind(fx.prop1)"
prop1err="@bind(vmsgs['p_prop1'])"><![CDATA[
<input type="text" value="@bind(prop1)"/>
<span textContent="@load(prop1err)"/>
<button onclick="@command('submit')">Submit</button>
]]></fragment>
- Line 3: Use the predefined
formBeanValidator
to validate a form.
Client-Side Property Validation
The Fragment component provides a novel validator called @jsvalidator
running at client side, accepting custom JavaScript functions for validation. The benefit is that there is no need to send requests to the server for each validation. However, since the validation logic will be exposed at client side, some simple check, such as empty checking or range checking, is recommended. The usage is like @validator
but it is effective only on applying to HTML elements. The text inside the parentheses is the name of the mentioned validation function. Two parameters are passed to the validation function. One is the user input, and the other is a validation message holder object. The validation function is expected to return a Boolean value to tell the component if the data is valid. Only the valid data will be sent to the server for further operations.
<fragment viewModel="..." prop1="@bind(vm.prop1)"><![CDATA[
<input type="text" value="@bind(prop1) @jsvalidator('validation')"/>
<span textContent="@load(vmsgs['prop1'])"/>
<script type="text/javascript">
function validation(val, vmsgs) {
var valid = doValidation(val);
vmsgs['prop1'] = valid ? '' : 'prop1 error';
return valid;
}
function doValidation(val) {
// omitted
}
</script>
]]></fragment>
- Line 2: Apply
@jsvalidator
directly to HTML elements. And use the declaredvalidation
function as a validation function. - Line 5-9: The
validation
function is declared here. The logic is very simple.
The Differences Between @validator and @jsvalidator
Catalogue | @validator | @jsvalidator |
---|---|---|
Validate at | Server side | Client side |
ZK form validation | Supported | Not supported |
Validation message holder | Initialized in validationMessages | An implicit vmsgs object |
@validator
relies on the server, while@jsvalidator
relies on the browser.@jsvalidator
does not support form validation.- The validation message holders are not the same. See the following section to know more.
For security concerns, we recommend you to use @validator
in most cases and choose @jsvalidator
if the validation needs an instant feedback such as password strength.
Validation Message Holder on Client-Side
The @jsvalidator
also supports validation messages. There is a predefined message holder object named vmsgs
in each Fragment component. This object accepts self-defined keys to get messages. You can retrieve the object from the second argument of a validation function; depending on the validation result you can fill out or clear messages.
You can use an implicit object (vmsgs
) to get the client-side invalid message; so you do not need to initialize a validationMessages holder object at the Fragment tag nor bind the invalid messages beforehand. Please note that the holder object is not shared with server side.
<fragment viewModel="..." prop1="@bind(vm.prop1)"><![CDATA[
// omitted
<span textContent="@load(vmsgs['prop1'])"/>
// omitted
]]></fragment>
- Line 3: Use the
vmsgs
directly.
Event Handling
You can attach DOM events on HTML elements to trigger commands of view models. The command of ViewModel will be executed and receive the corresponding event object.
Following is a quick lookup table of the relation between supported DOM events and ZK Event objects.
ZK Event object | DOM event |
---|---|
MouseEvent | onclick |
oncontextmenu | |
ondblclick | |
onmousedown | |
onmouseenter | |
onmouseleave | |
onmouseover | |
onmouseout | |
onmouseup | |
ondrag | |
KeyEvent | onkeydown |
onkeypress | |
onkeyup | |
InputEvent | onchange |
oninput | |
CheckEvent | onchange (checkbox) |
oninput (checkbox) | |
SelectionEvent | onselect |
DropEvent | ondrop |
Event | onblur |
onfocus | |
onfocusin | |
onfocusout |
To retrieve an event object, use a reserved keyword "event
" in arguments of @command
or apply annotation @ContextParam(ContextType.TRIGGER_EVENT)
on a parameter of the command method. For further information, check Retrieve Event Object. For properties of each event object, find out at: org.zkoss.zk.ui.event Javadoc.
<fragment viewModel="..."><![CDATA[
<button onclick="@command('cmd1', e=event)">Hit me!</button>
<input type="checkbox" onchange="@command('cmd2')"/>
]]></fragment>
- Line 2: Use a reserved keyword "
event
" in arguments.
public class EventVM {
// Method 1
@Command
public void cmd1(@BindingParam("e") MouseEvent e) {
// do something with event
// omitted
}
// Method 2
@Command
public void cmd2(@ContextParam(ContextType.TRIGGER_EVENT) CheckEvent e) {
// do something with event
// omitted
}
}
- Line 4: Retrieve the binding parameter
e
as an event object. - Line 11: Apply a
@ContextParam
annotation to retrieve the triggering event object.
Summary
In this article, we show the interaction between Fragment component and ZK MVVM mechanism. You can validate native HTML elements by using @validator
, applying form binding, using built-in JSR 303 bean validators or trying a client-side @jsvalidator
. You can display the invalid messages after each validation.
In the second part we describe the event object of the relative DOM events. You can get more details from the event object such as mouse cursor position, pressed keys, entered text, and selected text.
The complete demo source code is available on GitHub.
References
- Client Binding with ZK MVVM for your eyes only
- ZK MVVM Reference - Validator
- org.zkoss.zk.ui.event Javadoc
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |