Use VueJS With ZK9 EmbeddedZK"
(→Demo) |
m |
||
(16 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
{{Template:Smalltalk_Author| | {{Template:Smalltalk_Author| | ||
|author=James Chu, Potix Corporation | |author=James Chu, Potix Corporation | ||
− | |date=January | + | |date=January 31, 2020 |
|version='''ZK''' 9.0.0 | |version='''ZK''' 9.0.0 | ||
}} | }} | ||
= Overview = | = Overview = | ||
− | In the recently released ZK9, we provide a new way to integrate applications with ZK and front-end frameworks - | + | In the recently released ZK9, we provide a new way to integrate applications with ZK and front-end frameworks - Embedded ZK. For instance, we can integrate Vue. [https://vuejs.org/ VueJS] is a progressive framework for building user interfaces. With the Embedded ZK feature in ZK9, we could easily combine VueJS and ZK together. In the following demo project, we will use [http://books.zkoss.org/zk-mvvm-book/8.0/data_binding/client_binding_api.html ZK client-side binding], [https://www.zkoss.org/wiki/ZK_Developer%27s_Reference/Integration/ZK_Embedded/Embedded_ZK_Application Embedded ZK], [https://getbootstrap.com/ Bootstrap] and [https://vuejs.org/ VueJS] to demonstrate how this can be done. |
− | + | [[File:ZK9_Embedded_With_VueJS01.png | 800px | center]] | |
− | [[File: | ||
− | |||
− | |||
− | = | + | = Prepare data and ZK settings (Java) = |
− | + | As we can see, this demo is a forum project. This demo contains several parts on the server-side: | |
− | |||
− | |||
− | + | 1. Data object | |
− | |||
− | + | 2. View Models | |
− | + | 3. Define ZK Binder in ZUL files | |
− | |||
− | + | 4. Enable Embedded ZK | |
− | |||
− | == | + | == Data Object == |
− | + | There are two main entity classes - User and Article. | |
− | === | + | ''org.zkoss.demo.forum.entity.User'' |
− | + | <source lang="java"> | |
+ | public class User { | ||
+ | private int uid; | ||
+ | private String account; | ||
+ | private String password; | ||
+ | private String name; | ||
+ | //... getters/setters are omitted | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | ''org.zkoss.demo.forum.entity.Article'' | ||
+ | <source lang="java"> | ||
+ | public class Article { | ||
+ | private int uid; | ||
+ | private User user; | ||
+ | private String subject; | ||
+ | private String thumbnail; | ||
+ | private String content; | ||
+ | private Date lastEditedTime; | ||
+ | //... getters/setters are omitted | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | When using ZK client-binding, the two data objects would be converted into '''JSON object'''. Therefore we could inject the data into Vue components later. | ||
+ | |||
+ | == ZK View Models and ZUL Files== | ||
+ | In the view model, we need to prepare the binder and define the commands that would be called on the client-side. | ||
− | = | + | === Client-side Binding in View Model (Server to Client) === |
− | + | ''org.zkoss.demo.forum.viewmodel.ArticleListVM'' | |
+ | <source lang="java" highlight="1,2,3"> | ||
+ | @NotifyCommand(value = "toC_Articles", onChange = "_vm_.articles") | ||
+ | @ToClientCommand({ "toC_Articles"}) | ||
+ | @ToServerCommand({ "loadArticles", "loadArticleById"}) | ||
+ | public class ArticleListVM { | ||
+ | @Command | ||
+ | @NotifyChange("articles") | ||
+ | public void loadArticles() { | ||
+ | articles = articleService.getRecentArticles(); | ||
+ | } | ||
+ | //omitted | ||
+ | } | ||
+ | </source> | ||
+ | Line 1 & 2: When the property "articles" is changed, ZK would fire a client command "toC_Articles" to the client-side. | ||
− | + | Line 3: Allow client-side binders to call specific commands. | |
− | == | + | === Define ZK Binder in ZUL files === |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ''src/main/resources/web/zul/articles.zul'' | |
− | + | <source lang="xml"> | |
− | + | <div id="articles-binder" viewModel="@id('vm') @init('org.zkoss.demo.forum.viewmodel.ArticleListVM')" /> | |
− | <source lang="xml">< | + | </source> |
− | The | + | The id "articles-binder" is defined for the ZK Client-binding Javascript API. |
+ | == Enable Embedded ZK == | ||
+ | We use the [https://www.zkoss.org/wiki/ZK_Configuration_Reference/zk.xml/The_Library_Properties/org.zkoss.web.servlet.http.embedded.enabled library property] to enable Embedded ZK. | ||
+ | |||
+ | ''zk.xml'' | ||
<source lang="xml"> | <source lang="xml"> | ||
− | < | + | <library-property> |
− | < | + | <name>org.zkoss.web.servlet.http.embedded.enabled</name> |
− | + | <value>true</value> | |
− | + | </library-property> | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | </ | ||
</source> | </source> | ||
− | + | = Integrate with VueJS (Javascript) = | |
− | + | Before integrating with VueJS, we need to load embedded ZK in the HTML file. | |
− | === | + | == Sets Embedded ZK == |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ''src/main/resources/static/index.html'' | |
+ | |||
+ | <source lang="xml"> | ||
+ | <body> | ||
+ | <!-- omitted --> | ||
+ | <div id="embeddedZK"></div> | ||
+ | <!-- omitted --> | ||
+ | </body> | ||
</source> | </source> | ||
− | |||
− | + | Use a div to embed ZK binder DOM ($articles-binder). | |
− | + | ||
+ | ''src/main/resources/static/js/app.js'' | ||
− | <source lang=" | + | <source lang="javascript" highlight="1"> |
− | + | zEmbedded.load('embeddedZK', '/articles'); | |
− | + | window.addEventListener('load', function(){ | |
− | + | zk.afterMount(function () { | |
− | + | // Initialize Vue Components after ZK is mounted | |
− | + | }); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
</source> | </source> | ||
− | |||
− | + | Line 1: '/articles' would redirect to the specific URL path (articles.zul) | |
− | <source lang=" | + | Notice that all the data transfer from the ZK server to the client should wait for ZK being mounted. |
− | + | ||
+ | == Use ZK Client-side binding in Vue (Client to Server) == | ||
+ | After loading the embedded ZK, we used client-side binding in Vue instances. | ||
+ | |||
+ | 1. To trigger commands in ZK Server, we used '''Binder.command(command, args, ...)'''. | ||
+ | |||
+ | 2. To get the result from the ZK server, we used '''Binder.after(command, callback)''' to register the callback function. | ||
+ | |||
+ | ''src/main/resources/static/js/app.js'' | ||
+ | |||
+ | <source lang="javascript" highlight="2,4,9,14,16,18,19"> | ||
+ | // inside zk.afterMount | ||
+ | var articlesBinder = zkbind.$('$articles-binder'); | ||
+ | new Vue({ | ||
+ | el: '#articles', | ||
+ | data: { | ||
+ | articles: [] | ||
+ | }, | ||
+ | beforeMount() { | ||
+ | this.loadArticles(); | ||
+ | }, | ||
+ | methods: { | ||
+ | loadArticles () { | ||
+ | var self = this, | ||
+ | changeArticles = function (data) { | ||
+ | self.articles = data; | ||
+ | articlesBinder.unAfter('toC_Articles', changeArticles); | ||
+ | }; | ||
+ | articlesBinder.after('toC_Articles', changeArticles); | ||
+ | articlesBinder.command('loadArticles'); | ||
+ | } | ||
+ | //omitted | ||
+ | } | ||
+ | }); | ||
</source> | </source> | ||
− | |||
− | + | Line 2: Looking for the ZK binder. | |
− | <source lang=" | + | |
− | + | Line 4: Vue dom selector. | |
+ | |||
+ | Line 9: Trigger the loading method before Vue is mounted. | ||
+ | |||
+ | Line 14: Prepare a callback function to update articles. | ||
+ | |||
+ | Line 16: Unregister the callback. | ||
+ | |||
+ | Line 18: Register a callback function, it would be triggered when receiving the client command - "toC_Articles". | ||
+ | |||
+ | Line 19: Use ZK Client-binding API to trigger a command on the server-side. | ||
+ | |||
+ | Since the data "articles" is a list, we use [https://vuejs.org/v2/guide/list.html List Rendering] in VueJs. | ||
+ | |||
+ | ''src/main/resources/static/index.html'' | ||
+ | |||
+ | <source lang="xml" highlight="3,5"> | ||
+ | <div id="articles" class="..."> | ||
+ | <!-- omitted --> | ||
+ | <article-block v-for="article in articles" | ||
+ | v-bind:key="article.uid" v-bind:subject="article.subject" v-bind:thumbnail="article.thumbnail" | ||
+ | v-bind:username="article.user.name" v-bind:time="article.publishedTime" | ||
+ | v-on:view="view(article.uid)"> | ||
+ | </article-block> | ||
+ | <!-- omitted --> | ||
+ | </div> | ||
</source> | </source> | ||
− | |||
− | |||
− | |||
− | |||
+ | Line 3: "article-block" is a Vue component, and we use the List rendering | ||
− | + | Line 5: the property "article.user.name" is fully referred to the data from Java Bean | |
− | + | = Summary = | |
+ | The core value of ZK is to allow you to build a Web UI quickly with pure Java. However, in some cases, you may need to integrate a specific 3rd-party front-end framework with ZK. With embedded ZK, using such front-end frameworks with ZK becomes easier. I hope this article will give you some hints on how you can get this done. | ||
+ | Please feel free to leave comments below or create a discussion on [http://forum.zkoss.org/questions/ ZK forum]. | ||
− | + | = Download = | |
− | You can download | + | You can download all of the source code for this demo in [https://github.com/zkoss-demo/client-binding-demo-vuejs Github] |
{{Template:CommentedSmalltalk_Footer_new| | {{Template:CommentedSmalltalk_Footer_new| |
Latest revision as of 14:41, 20 June 2023
James Chu, Potix Corporation
January 31, 2020
ZK 9.0.0
Overview
In the recently released ZK9, we provide a new way to integrate applications with ZK and front-end frameworks - Embedded ZK. For instance, we can integrate Vue. VueJS is a progressive framework for building user interfaces. With the Embedded ZK feature in ZK9, we could easily combine VueJS and ZK together. In the following demo project, we will use ZK client-side binding, Embedded ZK, Bootstrap and VueJS to demonstrate how this can be done.
Prepare data and ZK settings (Java)
As we can see, this demo is a forum project. This demo contains several parts on the server-side:
1. Data object
2. View Models
3. Define ZK Binder in ZUL files
4. Enable Embedded ZK
Data Object
There are two main entity classes - User and Article.
org.zkoss.demo.forum.entity.User
public class User {
private int uid;
private String account;
private String password;
private String name;
//... getters/setters are omitted
}
org.zkoss.demo.forum.entity.Article
public class Article {
private int uid;
private User user;
private String subject;
private String thumbnail;
private String content;
private Date lastEditedTime;
//... getters/setters are omitted
}
When using ZK client-binding, the two data objects would be converted into JSON object. Therefore we could inject the data into Vue components later.
ZK View Models and ZUL Files
In the view model, we need to prepare the binder and define the commands that would be called on the client-side.
Client-side Binding in View Model (Server to Client)
org.zkoss.demo.forum.viewmodel.ArticleListVM
@NotifyCommand(value = "toC_Articles", onChange = "_vm_.articles")
@ToClientCommand({ "toC_Articles"})
@ToServerCommand({ "loadArticles", "loadArticleById"})
public class ArticleListVM {
@Command
@NotifyChange("articles")
public void loadArticles() {
articles = articleService.getRecentArticles();
}
//omitted
}
Line 1 & 2: When the property "articles" is changed, ZK would fire a client command "toC_Articles" to the client-side.
Line 3: Allow client-side binders to call specific commands.
Define ZK Binder in ZUL files
src/main/resources/web/zul/articles.zul
<div id="articles-binder" viewModel="@id('vm') @init('org.zkoss.demo.forum.viewmodel.ArticleListVM')" />
The id "articles-binder" is defined for the ZK Client-binding Javascript API.
Enable Embedded ZK
We use the library property to enable Embedded ZK.
zk.xml
<library-property>
<name>org.zkoss.web.servlet.http.embedded.enabled</name>
<value>true</value>
</library-property>
Integrate with VueJS (Javascript)
Before integrating with VueJS, we need to load embedded ZK in the HTML file.
Sets Embedded ZK
src/main/resources/static/index.html
<body>
<!-- omitted -->
<div id="embeddedZK"></div>
<!-- omitted -->
</body>
Use a div to embed ZK binder DOM ($articles-binder).
src/main/resources/static/js/app.js
zEmbedded.load('embeddedZK', '/articles');
window.addEventListener('load', function(){
zk.afterMount(function () {
// Initialize Vue Components after ZK is mounted
});
}
Line 1: '/articles' would redirect to the specific URL path (articles.zul) Notice that all the data transfer from the ZK server to the client should wait for ZK being mounted.
Use ZK Client-side binding in Vue (Client to Server)
After loading the embedded ZK, we used client-side binding in Vue instances.
1. To trigger commands in ZK Server, we used Binder.command(command, args, ...).
2. To get the result from the ZK server, we used Binder.after(command, callback) to register the callback function.
src/main/resources/static/js/app.js
// inside zk.afterMount
var articlesBinder = zkbind.$('$articles-binder');
new Vue({
el: '#articles',
data: {
articles: []
},
beforeMount() {
this.loadArticles();
},
methods: {
loadArticles () {
var self = this,
changeArticles = function (data) {
self.articles = data;
articlesBinder.unAfter('toC_Articles', changeArticles);
};
articlesBinder.after('toC_Articles', changeArticles);
articlesBinder.command('loadArticles');
}
//omitted
}
});
Line 2: Looking for the ZK binder.
Line 4: Vue dom selector.
Line 9: Trigger the loading method before Vue is mounted.
Line 14: Prepare a callback function to update articles.
Line 16: Unregister the callback.
Line 18: Register a callback function, it would be triggered when receiving the client command - "toC_Articles".
Line 19: Use ZK Client-binding API to trigger a command on the server-side.
Since the data "articles" is a list, we use List Rendering in VueJs.
src/main/resources/static/index.html
<div id="articles" class="...">
<!-- omitted -->
<article-block v-for="article in articles"
v-bind:key="article.uid" v-bind:subject="article.subject" v-bind:thumbnail="article.thumbnail"
v-bind:username="article.user.name" v-bind:time="article.publishedTime"
v-on:view="view(article.uid)">
</article-block>
<!-- omitted -->
</div>
Line 3: "article-block" is a Vue component, and we use the List rendering
Line 5: the property "article.user.name" is fully referred to the data from Java Bean
Summary
The core value of ZK is to allow you to build a Web UI quickly with pure Java. However, in some cases, you may need to integrate a specific 3rd-party front-end framework with ZK. With embedded ZK, using such front-end frameworks with ZK becomes easier. I hope this article will give you some hints on how you can get this done. Please feel free to leave comments below or create a discussion on ZK forum.
Download
You can download all of the source code for this demo in Github
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |