Introduction
This post is about how to create a new ZK Component, step by step, with a very simple component 'errmsg' in Eclipse.
The errmsg component will display specified msg in error style and store the specified description.
After this article, you can also refer to Index Page of ZK CDT (Component Development Tutorial) Walkthrough to see more advanced articles.
The Steps
Step 1
This is starts from http://ben-bai.blogspot.tw/2012/06/zk-quick-start.html, a simple Dynamic Web Project with basic ZK jars.
Step 2
Some files should at the pre-defined location,
where lang-addon.xml should under classpath/metainfo/zk,
and the widget js/css files should under classpath/web/js
You can simply create a folder under project root and prepare the folders described above,
then edit the Project -> Properties to add it as Source folder
Finally the project structure are as below:
where the folders under CustomComponentsResources will be copied to classpath after compile
Step 3
Prepare the lang-addon.xml to define this component,
please refer to the inline-document
lang-addon.xml
<!-- ZK will load this file
(classpath/metainfo/zk/lang-addon.xml) automatically -->
<language-addon>
<!-- addon name,
required, it's better to be unique -->
<addon-name>custom</addon-name>
<!-- specifies the name of a language definition
should be unique in a language definition,
xul/html is predefinied language in ZK
so can be used in lang-addon directly -->
<language-name>xul/html</language-name>
<!-- version
optional,
if the version specified in version-class is not
the same as version-uid, or the real ZK version is smaller
then zk-version, the addon will be ignored -->
<version>
<version-class>custom.zk.Version</version-class>
<version-uid>0.0.1</version-uid>
<zk-version>5.0.0</zk-version><!-- or later -->
</version>
<!-- define a component -->
<component>
<!-- the tag name of this component
required,
must be unique -->
<component-name>errmsg</component-name>
<!-- fully-qualified java class name at server side
required for a new component that not extends another component -->
<component-class>custom.zk.components.Errmsg</component-class>
<!-- widget class, 'custom.zk.components.Errmsg'
also specify the
package of widget class 'custom.zk.components'
required for a new component that not extends another component
from my test,
when you say a widget class is custom.zk.components.Errmsg
it denotes there should have a file
web/js/custom/zk/components/Errmsg.js under classpath,
and have "<package name="custom.zk.components" ...>...</package>"
in web/js/custom/zk/components/zk.wpd
and "custom.zk.components.Errmsg = ..."
in Errmsg.js to define that client widget
You may try play around to find whether you can
make them different, but it's better to let them
sync even if you can make them different -->
<widget-class>custom.zk.components.Errmsg</widget-class>
<!-- mold
required for a new component that not extends another component
or has self widget-class
a mold denotes the files that to render and style this comopnent -->
<mold>
<!-- default mold is required -->
<mold-name>default</mold-name>
<!-- relative path based on widget-class' path
(web/js/custom/zk/components/)
where errmsg.js (required) contains a function that
will render the html of the comopnent,
errmsg.css.dsp (optional) contains
css styles of this component -->
<mold-uri>mold/errmsg.js</mold-uri>
<css-uri>css/errmsg.css.dsp</css-uri>
</mold>
</component>
</language-addon>
Step 4
Prepare the widget js file for this component
Errmsg.js
//error message widget class
//this file will be loaded because
//the widget-class -- 'custom.zk.components.Errmsg'
//specified in lang-addon.xml and zk.wpd
custom.zk.components.Errmsg = zk.$extends(zul.Widget, {
// block for define attributes
// where 'anAttr: null' in this block will
// generate 3 items in this widget
// 1. this._anAttr
// 2. this.setAnAttr(value)
// 3. this.getAnAttr(value)
// 'anAttr: function (v)' will also generate the 3 items above,
// the function will be called by setter,
// i.e., setAnAttr(value) {
// ...
// function(v)
// ...
// }
// so you can specify what you want to do while the setter is called
// for more information, please refer to
// http://www.zkoss.org/javadoc/latest/jsdoc/_global_/zk.html#$extends(zk.Class, _global_.Map, _global_.Map)
// http://www.zkoss.org/javadoc/latest/jsdoc/_global_/zk.html#define(zk.Class, _global_.Map)
$define: {
msg: function (v) {
var n;
if (v
&& (n = this.$n()))
n.innerHTML = v;
},
description: null
},
// function to provide css class
getZclass: function () {
var zcls = this._zclass;
return zcls? zcls : 'z-errmsg';
}
});
Step 5
Prepare the renderer js file / css style file for default mold
errmsg.js
//error message html renderer
//this file will be loaded because
//the package of widget-class -- 'custom.zk.components'
//and the mold-uri of mold -- 'mold/errmsg.js'
//specified in lang-addon.xml
function (out) {
// the rendered msg
var msg = this._msg;
// this.uuid is the default attribute that
// will assigned by ZK framework
// this.getZclass() is overridden in Errmsg.js
// after this line, the tmp result is
// <span id="xxxxx" class="z-errmsg">
out.push('<span id="', this.uuid,
'" class="', this.getZclass(), '">');
// output msg if exists
if (msg)
out.push(msg);
// output end tag of span
out.push('</span>');
// finally, the result will be
// <span id="xxxxx" class="z-errmsg">some message</span>
// or
// <span id="xxxxx" class="z-errmsg"></span>
}
errmsg.css.dsp
/* error message style */
/* this file will be loaded because */
/* the package of widget-class 'custom.zk.components' */
/* and the css-uri of mold 'css/errmsg.css.dsp' */
/* specified in lang-addon.xml */
.z-errmsg {
font-weight: bold;
font-size: 22px;
color: red;
}
Step 6
Prepare zk.wpd to config widget's loading
zk.wpd
<!-- this file define the package name and the order to load widgets -->
<!-- depends="zul" denotes this package should -->
<!-- be loaded after the zul package, -->
<!-- i.e., if you load this package but the zul package is not loaded, -->
<!-- the framework will load zul package first automatically -->
<package name="custom.zk.components" language="xul/html" depends="zul">
<widget name="Errmsg"/>
</package>
Step 7
Prepare the Version class to specify version of this addon and component class.
Version.java
package custom.zk;
// the Versio file that version UID will be compared
// with the version-uid specified in lang-addon.xml
public class Version {
/** Returns the version UID.
*/
public static final String UID = "0.0.1";
}
Errmsg.java
package custom.zk.components;
import org.zkoss.zul.impl.XulElement;
// this file will be loaded because the
// <component-class>custom.zk.components.Errmsg</component-class>
// specified in lang-addon.xml
public class Errmsg extends XulElement {
private String _msg;
private String _description;
public void setMsg (String msg) {
_msg = msg;
// this will call client side widget's setMsg(_msg)
smartUpdate("msg", _msg);
}
public String getMsg () {
return _msg;
}
public void setDescription (String description) {
_description = description;
// this will call client side widget's setDescription(_description)
smartUpdate("description", _description);
}
public String getDescription () {
return _description;
}
public String getZclass() {
return _zclass == null ? "z-errmsg" : _zclass;
}
//-- ComponentCtrl --//
// the renderProperties will be called by framework automatically,
// remember to render super's properties first
protected void renderProperties(org.zkoss.zk.ui.sys.ContentRenderer renderer)
throws java.io.IOException {
super.renderProperties(renderer);
// this will call client side widget's setMsg(_msg)
if (_msg != null)
render(renderer, "msg", _msg);
// this will call client side widget's setDescription(_description)
if (_description != null)
render(renderer, "description", _description);
}
}
Step 8
Finally use a zul file to test it
errmsg_component_test.zul
<zk>
<!-- an errmsg thst display msg and will -->
<!-- alert its discription while clicked -->
<!-- the id attribute is specified in the super class -->
<!-- the onClick event also listened by super class -->
<!-- we can just simply use them -->
<errmsg id="errMsg" msg="error"
description="this is a test message to test component errmsg"
onClick="alert(self.getDescription());" />
<!-- use a ZK button to change errmsg's property -->
<!-- the 'errMsg' below is an errmsg instance that has id 'errMsg' -->
<button label="test">
<attribute name="onClick">
errMsg.setMsg(" new message");
errMsg.setDescription(" new description");
</attribute>
</button>
</zk>
Export component(s) to a jar
Apply following steps to export component(s) to a jar file
File -> Export
Select Jar file -> Next
Select CustomComponentsResources and src, specify jar location then click Finish
Finally you can use the component in other ZK Project with the generated jar file.
Result
See demo on line
http://screencast.com/t/3LUWQOdn
Download
Full project:
https://github.com/benbai123/ZK_Practice/tree/master/Components/projects/Components_Development
Demo:
https://github.com/benbai123/ZK_Practice/blob/master/Components/demos/component_development/zk_custom_component__errmsg_demo.swf
Exported jar:
https://github.com/benbai123/ZK_Practice/blob/master/Components/projects/Components_Development/target/ZKCustomComponents.jar
References:
http://www.zkoss.org/javadoc/latest/jsdoc/_global_/zk.html#$extends(zk.Class, _global_.Map, _global_.Map)
http://www.zkoss.org/javadoc/latest/jsdoc/_global_/zk.html#define(zk.Class, _global_.Map)
http://books.zkoss.org/wiki/ZK_Client-side_Reference/Language_Definition
Thanks for sharing :)
ReplyDeleteThanks for your reply :)
Deleteits not very clear how to create component and neither how to use it!
ReplyDeleteits not a good pratice doing tutorials with something already made, we suposed to learn all those steps needed for creating components, if you put it all together is much like that maven or maybe ruby tutorials, you just hit a button, run a Ant Script and doesn't know anything about whats going on behind scenes!
its not a good way of learning new technologies.
Thanks for your opinion, but these are already the fewest steps to create the most basic part of a ZK Component.
DeleteBy the way, most of the explanation is in the comment ( // ... or
Hello! I want to create my own component but no matter how i do it, I keep getting the Processing... screen, and that's it.
ReplyDeleteI am using zk7 with Tomcat8 and java8u60
I would like to know why this keeps happening. If you require more information, please let me know
DeleteThis kind of issue is usually caused by js error, you can press F12 to open Developer Tools and check whether anything went wrong from console in modern browsers (e.g., Chrome or Firefox).
DeleteThe debugger shows no errors, only warnings that do not appear to influence the page.
DeleteIs the JS files correctly loaded? For example, assume their is a bind_ function then you can try add "console.log('test')" to see whether it output 'test' to browser console.
DeleteBefore i answer that (I've been away for about 3 days), I wanted to test something: I re-downloaded eclipse, I put it in a new folder, created a new workspace, installed zk studio and tried the whole thing again. The result is quite confusing. I get two different problems: the first one is the one already mentioned and the new one: I get com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence. I validated and revalidated my lang-addon.xml and it's fine. It's getting quite frustrating.
DeleteAs for the console.log() part, now i get these two errors:
1) TypeError: com.test.zul is undefined
2)uncaught exception: Unknown widget: com.test.zk.Stamp
I don't understand the part with "com.test.zul", as i don't remember writing this and nor do i see it in my project. Really confused right about now
You can also try to follow official document to create component. If it still not work, is it possible that upload your project somewhere (e.g., github) for investigation?
DeleteThe official document: http://books.zkoss.org/wiki/ZK_Component_Development_Essentials
By the way, you can Search -> Files to find com.test.zul in your project, probably ZK Studio generated something automatically for you.
Great Content!! Thank you for sharing this helpful information. Using.
ReplyDeleteIf you are an educational entrepreneur or thinking of a startup by launching an education app, so here I am representing some education App Ideas For Students. The App Ideas is leading web and Mobile App development. We provide the best IT Services at best rates. Contact us now!