Fragment"
(Created page with "{{Template:UnderConstruction}} {{ZKComponentReferencePageHeader}} = Fragment = *Demonstration: N/A = Employment/Purpose = <tt>Fragment</tt> is a ZK Component. = Example = <s...") |
RebeccaLai (talk | contribs) m |
||
(40 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
− | {{ | + | {{ZKComponentReferencePageHeader}} |
− | |||
= Fragment = | = Fragment = | ||
− | *Demonstration: N/A | + | * Demonstration: N/A |
+ | * Java API: <javadoc>org.zkoss.zkmax.zul.Fragment</javadoc> | ||
+ | * JavaScript API: <javadoc directory="jsdoc">zkmax.wgt.Fragment</javadoc> | ||
+ | * Style Guide: N/A | ||
+ | {{ZK EE}} | ||
− | = | + | = Purpose = |
− | < | + | <code>Fragment</code> is a ZK component which developers can combine native HTML elements with ZK data binding syntax to make the static page to be dynamic. |
+ | == Alternative== | ||
+ | To manipulate HTML elements dynamically, ZK supports several ways in addition to this component. Please refer to [[ZK_Developer%27s_Reference/UI_Patterns/HTML_Tags]] for more details. | ||
= Example = | = Example = | ||
+ | [[File:ZKComRef Fragment Example.png]] | ||
+ | <source lang="xml"> | ||
+ | <zk> | ||
+ | <fragment viewModel="@id('vm') @init('org.zkoss.fragment.demo.VM2')" 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> | ||
+ | </zk> | ||
+ | </source> | ||
+ | |||
+ | = Data Binding = | ||
+ | With Fragment Component, you can bind the properties of ViewModel. For instance, you can use ZK MVVM data binding to access the ViewModel on the native HTML elements. | ||
+ | == Enclose with CDATA== | ||
+ | Remember to mark the fragment content with the CDATA section to avoid being parsed by server-side binder and causing problems: | ||
+ | <syntaxhighlight lang='xml'> | ||
+ | <fragment><![CDATA[ | ||
+ | ... | ||
+ | ]]></fragment> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Supported Bindings == | ||
+ | |||
+ | These are the supported annotations: | ||
+ | * '''@save''' | ||
+ | syntax: @save([limited EL-expression]) | ||
+ | * '''@load''' | ||
+ | syntax: @load(limited EL-expression) | ||
+ | * '''@bind''' | ||
+ | syntax: @bind(limited EL-expression) | ||
+ | * '''@command''' | ||
+ | syntax: @command(mybean.myproperty, [arbitraryKey]=[limited EL-expression]) | ||
+ | * '''@global-command''' | ||
+ | syntax: @global-command(mybean.myproperty, [arbitraryKey]=[limited EL-expression]) | ||
+ | |||
+ | == Limited EL-expression == | ||
+ | Inside a fragment, it only supports partially, limited data binding expressions including bean dot notation, arithmetic operator, <code>!</code>, and <code>==</code> | ||
+ | |||
+ | = Put HTML as text content = | ||
+ | This component also provides a virtual <code>textContent</code> attribute for HTML elements to insert data into the tag. | ||
<source lang="xml" > | <source lang="xml" > | ||
− | <fragment> | + | <zk> |
− | + | <fragment viewModel="@id('vm') @init('org.zkoss.zktest.test2.F85_ZK_3681_Command_VM')" | |
− | + | status="@bind(vm.status)"><![CDATA[ | |
− | + | <div> | |
− | </fragment> | + | <input type="checkbox" onchange="@command('onCheck', checked=event.checked)" /> |
+ | Check this checkbox: <span textContent="@load(status)"/> | ||
+ | </div> | ||
+ | |||
+ | <div> | ||
+ | <button onclick="@global-command('callGlobal', text='Hello', num=1)">Call global (1)</button> | ||
+ | <button onclick="@global-command('callGlobal', text='World', num=2)">Call global (2)</button> | ||
+ | </div> | ||
+ | ]]></fragment> | ||
+ | </zk> | ||
+ | </source> | ||
+ | |||
+ | = Shadow Elements = | ||
+ | In this example, we use <code>if</code> and <code>forEach</code> tags together for condition and collection rendering. | ||
+ | |||
+ | <source lang="xml" > | ||
+ | <zk> | ||
+ | <fragment viewModel="@id('vm') @init('org.zkoss.zktest.test2.F85_ZK_3681_Shadow_VM')" | ||
+ | issues="@bind(vm.issues)"><![CDATA[ | ||
+ | <section> | ||
+ | <h1>My Issue List</h1> | ||
+ | <ul> | ||
+ | <forEach items="@load(issues)"> | ||
+ | <!-- There's a pre-defined variable "each" for convenience. --> | ||
+ | <li> | ||
+ | <!-- @bind(each) is wrong because each is just a temp variable in loops. --> | ||
+ | <input type="checkbox" checked="@load(each.isDone)" /> | ||
+ | <if test="@load(each.isDone)"> | ||
+ | <strike>[<span textContent="@load(each.id)"/>] | ||
+ | <span textContent="@load(each.description)"/></strike> | ||
+ | </if> | ||
+ | <!-- No else for now. --> | ||
+ | <if test="@load(!each.isDone)"> | ||
+ | [<span textContent="@load(each.id)"/>] | ||
+ | <span textContent="@load(each.description)"/> | ||
+ | </if> | ||
+ | </li> | ||
+ | </forEach> | ||
+ | </ul> | ||
+ | <section> | ||
+ | ]]></fragment> | ||
+ | </zk> | ||
+ | </source> | ||
+ | |||
+ | * For further details, please refer to [http://books.zkoss.org/zkessentials-book/master/shadow_components/index.html Shadow components] directly. | ||
+ | |||
+ | = Data Validation = | ||
+ | |||
+ | == Server-side Property/Form Validation == | ||
+ | To ensure data is correct and useful, we can leverage ZK's validators. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <zk> | ||
+ | <fragment viewModel="@id('vm') @init('org.zkoss.fragment.demo.VM1')" 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> | ||
+ | </zk> | ||
</source> | </source> | ||
+ | |||
+ | You can get the invalid message by assigning a self-defined key as an alias. In order to access invalidate messages by HTML elements, you can simply bind the messages onto Fragment properties. | ||
+ | |||
+ | Here we can use form-binding and form validators to validate all the fields. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <zk> | ||
+ | <fragment viewModel="@id('vm') @init('foo.BarVM')" validationMessages="@id('vmsgs')" | ||
+ | form="@id('fx') @load(vm.currentUser) @save(vm.currentUser, before='submit') @validator('formBeanValidator', prefix='p_')" | ||
+ | name="@bind(fx.name)" nameerror="@bind(vmsgs['p_name'])"><![CDATA[ | ||
+ | <input type="text" value="@bind(name)"/><span textContent="@load(nameerror)"/> | ||
+ | <button onclick="@command('submit')">Submit</button> | ||
+ | ]]></fragment> | ||
+ | </zk> | ||
+ | </source> | ||
+ | |||
+ | == Client-side Property Validation == | ||
+ | This component also provides a new <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 when applying HTML elements. | ||
+ | |||
+ | '''@jsvalidator''' | ||
+ | syntax: @jsvalidator(validation_function_name) | ||
+ | |||
+ | |||
+ | The following is the definition of custom JavaScript function. | ||
+ | ValidationFunction(val, vmsgs) | ||
+ | * val: The input data. | ||
+ | * vmsgs: | ||
+ | The validation message holder object. You can add an invalidate message by adding a new property. | ||
+ | If you want to clear the specific message, assign an empty string to the property. | ||
+ | * Returns: Boolean. True if the data is valid. | ||
+ | |||
+ | You can use an implicit object (vmsgs) to get the client-side invalid messages. The <code>@jsvalidator</code> has its own validation message holder not shared with server-side. | ||
+ | |||
+ | <source lang="xml"> | ||
+ | <zk> | ||
+ | <fragment viewModel="@id('vm') @init('foo.BarVM')" someprop="@bind(vm.prop1)"><![CDATA[ | ||
+ | <input type="text" value="@bind(someprop) @jsvalidator('validateExample')"/> | ||
+ | <span textContent="@load(vmsgs['foo'])"/> | ||
+ | ]]></fragment> | ||
+ | <script type="text/javascript"> | ||
+ | function validateExample(val, vmsgs) { | ||
+ | var isValid = someValidationProcess(val); | ||
+ | vmsgs['foo'] = isValid ? '' : 'Invalid value'; | ||
+ | return isValid; | ||
+ | } | ||
+ | </script> | ||
+ | </zk> | ||
+ | </source> | ||
+ | |||
+ | == The Differences Between @validator and @jsvalidator == | ||
+ | <div style="margin-left:auto;margin-right:auto;width:70%;"> | ||
+ | {| class='wikitable' | width="100%" | ||
+ | ! 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 | ||
+ | |} | ||
+ | </div> | ||
+ | # <code>@validator</code> relies on the server, while <code>@jsvalidator</code> relies on the browser. | ||
+ | # <code>@jsvalidator</code> does not support form validation. | ||
+ | # The validation message holders are not the same. | ||
+ | |||
+ | For security concerns, we recommend you to use server-side <code>@validator</code> in most cases and choose client-side <code>@jsvalidator</code> if the validation needs an instant feedback such as password strength, number range, and so on. | ||
+ | |||
+ | = Event Handling = | ||
+ | |||
+ | The command of ViewModel can be invoked by attaching DOM events with <code>@command</code> or <code>@global-command</code> on HTML elements. Once the DOM event is triggered (i.g. clicked or changed), the command of ViewModel will be executed and receive the corresponding event object. | ||
+ | |||
+ | You can get more details from the event object such as mouse cursor position, pressed keys, entered text, and selected text. | ||
+ | |||
+ | {| class='wikitable' | width="100%" | ||
+ | ! ZK Event object | ||
+ | ! DOM event | ||
+ | |- | ||
+ | | rowspan="10" | <javadoc>org.zkoss.zk.ui.event.MouseEvent</javadoc> | ||
+ | | onclick | ||
+ | |- | ||
+ | | oncontextmenu | ||
+ | |- | ||
+ | | ondblclick | ||
+ | |- | ||
+ | | onmousedown | ||
+ | |- | ||
+ | | onmouseenter | ||
+ | |- | ||
+ | | onmouseleave | ||
+ | |- | ||
+ | | onmouseover | ||
+ | |- | ||
+ | | onmouseout | ||
+ | |- | ||
+ | | onmouseup | ||
+ | |- | ||
+ | | ondrag | ||
+ | |- | ||
+ | | rowspan="3" | <javadoc>org.zkoss.zk.ui.event.KeyEvent</javadoc> | ||
+ | | onkeydown | ||
+ | |- | ||
+ | | onkeypress | ||
+ | |- | ||
+ | | onkeyup | ||
+ | |- | ||
+ | | rowspan="2" | <javadoc>org.zkoss.zk.ui.event.InputEvent</javadoc> | ||
+ | | onchange | ||
+ | |- | ||
+ | | oninput | ||
+ | |- | ||
+ | | rowspan="2" | <javadoc>org.zkoss.zk.ui.event.CheckEvent</javadoc> | ||
+ | | onchange (checkbox) | ||
+ | |- | ||
+ | | oninput (checkbox) | ||
+ | |- | ||
+ | | <javadoc>org.zkoss.zk.ui.event.SelectionEvent</javadoc> | ||
+ | | onselect | ||
+ | |- | ||
+ | | <javadoc>org.zkoss.zk.ui.event.DropEvent</javadoc> | ||
+ | | ondrop | ||
+ | |- | ||
+ | | rowspan="4" | <javadoc>org.zkoss.zk.ui.event.Event</javadoc> | ||
+ | | onblur | ||
+ | |- | ||
+ | | onfocus | ||
+ | |- | ||
+ | | onfocusin | ||
+ | |- | ||
+ | | onfocusout | ||
+ | |} | ||
+ | |||
+ | * For further details about how to retrieve the event object, please refer to [http://books.zkoss.org/zk-mvvm-book/8.0/advanced/parameters.html#retrieve-event-object Retrieve Event Object] directly. | ||
+ | |||
+ | = Properties = | ||
+ | * '''content''': specify the content of this component. | ||
+ | * '''src''': specify the URI of an external content file. The file encoding is assumed to be UTF-8. | ||
+ | * '''recoverId''': specify the recover ID. | ||
=Supported Events= | =Supported Events= | ||
− | {| | + | {| class='wikitable' | width="100%" |
! <center>Name</center> | ! <center>Name</center> | ||
! <center>Event Type</center> | ! <center>Event Type</center> | ||
|- | |- | ||
− | | | + | | <center><code>onRecover</code></center> |
− | | | + | | '''Event:''' <javadoc>org.zkoss.zk.ui.event.Event</javadoc> |
+ | |||
+ | Represents an event sent back to the server caused by an offline recovery. | ||
|} | |} | ||
=Supported Children= | =Supported Children= | ||
− | + | None | |
− | |||
=Use Cases= | =Use Cases= | ||
− | {| | + | {| class='wikitable' | width="100%" |
! Version !! Description !! Example Location | ! Version !! Description !! Example Location | ||
|- | |- | ||
− | | | + | | 8.5+ |
− | | | + | | Data binding, Shadow elements |
− | | | + | | [http://blog.zkoss.org/2016/11/15/client-binding-with-zk-mvvm-for-your-eyes-only/ Client Binding with ZK MVVM for your eyes only] |
+ | |- | ||
+ | | 8.5+ | ||
+ | | Data validation, Event handling | ||
+ | | [https://www.zkoss.org/wiki/Small_Talks/2017/July/Advanced_Usage_of_Fragment_Component Advanced Usage of Fragment Component] | ||
|} | |} | ||
Line 46: | Line 303: | ||
{{LastUpdated}} | {{LastUpdated}} | ||
− | {| | + | {| class='wikitable' | width="100%" |
! Version !! Date !! Content | ! Version !! Date !! Content | ||
|- | |- |
Latest revision as of 06:03, 5 February 2024
Fragment
- Available for ZK:
Purpose
Fragment
is a ZK component which developers can combine native HTML elements with ZK data binding syntax to make the static page to be dynamic.
Alternative
To manipulate HTML elements dynamically, ZK supports several ways in addition to this component. Please refer to ZK_Developer's_Reference/UI_Patterns/HTML_Tags for more details.
Example
<zk>
<fragment viewModel="@id('vm') @init('org.zkoss.fragment.demo.VM2')" 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>
</zk>
Data Binding
With Fragment Component, you can bind the properties of ViewModel. For instance, you can use ZK MVVM data binding to access the ViewModel on the native HTML elements.
Enclose with CDATA
Remember to mark the fragment content with the CDATA section to avoid being parsed by server-side binder and causing problems:
<fragment><![CDATA[
...
]]></fragment>
Supported Bindings
These are the supported annotations:
- @save
syntax: @save([limited EL-expression])
- @load
syntax: @load(limited EL-expression)
- @bind
syntax: @bind(limited EL-expression)
- @command
syntax: @command(mybean.myproperty, [arbitraryKey]=[limited EL-expression])
- @global-command
syntax: @global-command(mybean.myproperty, [arbitraryKey]=[limited EL-expression])
Limited EL-expression
Inside a fragment, it only supports partially, limited data binding expressions including bean dot notation, arithmetic operator, !
, and ==
Put HTML as text content
This component also provides a virtual textContent
attribute for HTML elements to insert data into the tag.
<zk>
<fragment viewModel="@id('vm') @init('org.zkoss.zktest.test2.F85_ZK_3681_Command_VM')"
status="@bind(vm.status)"><![CDATA[
<div>
<input type="checkbox" onchange="@command('onCheck', checked=event.checked)" />
Check this checkbox: <span textContent="@load(status)"/>
</div>
<div>
<button onclick="@global-command('callGlobal', text='Hello', num=1)">Call global (1)</button>
<button onclick="@global-command('callGlobal', text='World', num=2)">Call global (2)</button>
</div>
]]></fragment>
</zk>
Shadow Elements
In this example, we use if
and forEach
tags together for condition and collection rendering.
<zk>
<fragment viewModel="@id('vm') @init('org.zkoss.zktest.test2.F85_ZK_3681_Shadow_VM')"
issues="@bind(vm.issues)"><![CDATA[
<section>
<h1>My Issue List</h1>
<ul>
<forEach items="@load(issues)">
<!-- There's a pre-defined variable "each" for convenience. -->
<li>
<!-- @bind(each) is wrong because each is just a temp variable in loops. -->
<input type="checkbox" checked="@load(each.isDone)" />
<if test="@load(each.isDone)">
<strike>[<span textContent="@load(each.id)"/>]
<span textContent="@load(each.description)"/></strike>
</if>
<!-- No else for now. -->
<if test="@load(!each.isDone)">
[<span textContent="@load(each.id)"/>]
<span textContent="@load(each.description)"/>
</if>
</li>
</forEach>
</ul>
<section>
]]></fragment>
</zk>
- For further details, please refer to Shadow components directly.
Data Validation
Server-side Property/Form Validation
To ensure data is correct and useful, we can leverage ZK's validators.
<zk>
<fragment viewModel="@id('vm') @init('org.zkoss.fragment.demo.VM1')" 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>
</zk>
You can get the invalid message by assigning a self-defined key as an alias. In order to access invalidate messages by HTML elements, you can simply bind the messages onto Fragment properties.
Here we can use form-binding and form validators to validate all the fields.
<zk>
<fragment viewModel="@id('vm') @init('foo.BarVM')" validationMessages="@id('vmsgs')"
form="@id('fx') @load(vm.currentUser) @save(vm.currentUser, before='submit') @validator('formBeanValidator', prefix='p_')"
name="@bind(fx.name)" nameerror="@bind(vmsgs['p_name'])"><![CDATA[
<input type="text" value="@bind(name)"/><span textContent="@load(nameerror)"/>
<button onclick="@command('submit')">Submit</button>
]]></fragment>
</zk>
Client-side Property Validation
This component also provides a new @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 when applying HTML elements.
@jsvalidator
syntax: @jsvalidator(validation_function_name)
The following is the definition of custom JavaScript function.
ValidationFunction(val, vmsgs) * val: The input data. * vmsgs: The validation message holder object. You can add an invalidate message by adding a new property. If you want to clear the specific message, assign an empty string to the property. * Returns: Boolean. True if the data is valid.
You can use an implicit object (vmsgs) to get the client-side invalid messages. The @jsvalidator
has its own validation message holder not shared with server-side.
<zk>
<fragment viewModel="@id('vm') @init('foo.BarVM')" someprop="@bind(vm.prop1)"><![CDATA[
<input type="text" value="@bind(someprop) @jsvalidator('validateExample')"/>
<span textContent="@load(vmsgs['foo'])"/>
]]></fragment>
<script type="text/javascript">
function validateExample(val, vmsgs) {
var isValid = someValidationProcess(val);
vmsgs['foo'] = isValid ? '' : 'Invalid value';
return isValid;
}
</script>
</zk>
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.
For security concerns, we recommend you to use server-side @validator
in most cases and choose client-side @jsvalidator
if the validation needs an instant feedback such as password strength, number range, and so on.
Event Handling
The command of ViewModel can be invoked by attaching DOM events with @command
or @global-command
on HTML elements. Once the DOM event is triggered (i.g. clicked or changed), the command of ViewModel will be executed and receive the corresponding event object.
You can get more details from the event object such as mouse cursor position, pressed keys, entered text, and selected text.
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 |
- For further details about how to retrieve the event object, please refer to Retrieve Event Object directly.
Properties
- content: specify the content of this component.
- src: specify the URI of an external content file. The file encoding is assumed to be UTF-8.
- recoverId: specify the recover ID.
Supported Events
onRecover |
Event: Event
Represents an event sent back to the server caused by an offline recovery. |
Supported Children
None
Use Cases
Version | Description | Example Location |
---|---|---|
8.5+ | Data binding, Shadow elements | Client Binding with ZK MVVM for your eyes only |
8.5+ | Data validation, Event handling | Advanced Usage of Fragment Component |
Version History
Version | Date | Content |
---|---|---|
8.5 | 2017/09/21 | Add the new Fragment component |