Smalltalk-draft"

From Documentation
Line 6: Line 6:
  
 
= Overview =
 
= Overview =
 
= React =
 
  
 
[https://reactjs.org/ React] is a JavaScript library for building user interfaces. We can use React as a front-end UI and use ZK as a pure backend. In this small talk, I will show you how to integrate React with ZK using the [https://books.zkoss.org/zk-mvvm-book/8.0/data_binding/client_binding_api.html client binding API] step by step.
 
[https://reactjs.org/ React] is a JavaScript library for building user interfaces. We can use React as a front-end UI and use ZK as a pure backend. In this small talk, I will show you how to integrate React with ZK using the [https://books.zkoss.org/zk-mvvm-book/8.0/data_binding/client_binding_api.html client binding API] step by step.
Line 15: Line 13:
 
= Load data from ZK =
 
= Load data from ZK =
  
We need to create a View Model to use the client binding feature in React.  
+
We need to create a View Model to use the client binding feature in React.
  
 
== Create a ViewModel (VM) in ZK ==
 
== Create a ViewModel (VM) in ZK ==
Line 46: Line 44:
 
== Set Client Binding Annotations ==
 
== Set Client Binding Annotations ==
  
 +
In order to get the <code>vm.products</code> from the client, we need to add some annotation to the IndexVM.
 +
 +
'''IndexVM.java'''
 +
<source lang="java" high="2,5">
 +
@NotifyCommands({
 +
@NotifyCommand(value = "getProducts", onChange = "_vm_.products")
 +
})
 +
@ToServerCommand({"tipProducts", "placeOrder"})
 +
@ToClientCommand({"getProducts"})
 +
@VariableResolver(DelegatingVariableResolver.class)
 +
public class IndexVM {
 +
  // omitted
 +
</source>
 +
* LIne 2: Add a <code>@NotifyCommand</code> and listen to <code>_vm_.products</code> changes (<em>_vm_</em> means the VM object)
 +
* Line 5: Register a client command so the client can call <code>getProducts</code>. ZK client binding uses whitelist so no command is allowed to be called from the client by default.
 +
 +
Once we set, we can get the property from the client. Let's see how we get the <code>products</code> from ZK.
 +
 +
== Use Client-Binding API in React ==
 +
 +
First, we need to use the ViewModel in zul, and create a root element for React.
 +
 +
'''index.zul'''
 +
<source lang="xml" high="2, 3">
 +
<zk xmlns:n="native">
 +
    <div id="main" viewModel="@id('vm') @init('react.vm.IndexVM')">
 +
        <n:div id="root"/>
 +
    </div>
 +
</zk>
 +
</source>
 +
* Line 2: The <code>id</code> property is needed for client binding to get the correct VM.
 +
* Line 3: We have created a native DIV element for React to render.
 +
 +
We can use [http://books.zkoss.org/zk-mvvm-book/8.0/data_binding/client_binding_api.html#on-clientside binder.after] to get products from ZK.
 +
 +
<source lang="js">
 +
zkbind.$('$main').after('getProducts', function (data) {
 +
    // the data is vm.products
 +
    // and this function will be called each time vm.products is changed
 +
});
 +
</source>
  
 
The react-shopping-cart loads JSON data a server. A method <code>fetchProducts</code> initiates <code>axios.get</code> to make an AJAX request.
 
The react-shopping-cart loads JSON data a server. A method <code>fetchProducts</code> initiates <code>axios.get</code> to make an AJAX request.
Line 59: Line 98:
 
</source>
 
</source>
  
We can use client binding API to request with ZK instead.
+
We can use client binding API to request with ZK instead. I wrote a utility class to handle it for convenience.
 +
 
 +
'''zkBinder.js'''
 +
<source lang="js">
 +
function getBinder(name) {
 +
  return window.zkbind && window.zkbind.$(name);
 +
}
 +
 
 +
export default {
 +
  after(name, event, callback) {
 +
    let binder = getBinder(name);
 +
    if (binder) {
 +
      binder.after(event, callback);
 +
      return true;
 +
    }
 +
    return false;
 +
  },
 +
  // omitted
 +
</source>
 +
 
 +
By default, ZK uses one-way binding, so the function is bound to the property. To simulate a one-time request, I need to trigger a command first, the command just notifies ZK that it changes (but actually not) in order to trigger <code>@NotifyCommand</code>
 +
 
  
  
 +
'''react-shopping-cart/src/services/shelf/actions.js'''
 +
<source lang="js">
 +
export const fetchProducts = (filters, sortBy, callback) => dispatch => {
 +
  return axios
 +
    .get(productsAPI)
 +
    .then(res => {
 +
      let { products } = res.data;
 +
// omitted
 +
</source>
  
 
= Submit data to ZK =
 
= Submit data to ZK =

Revision as of 04:08, 7 January 2020

udyhuang

Author
Rudy Huang, Engineer, Potix Corporation
Date
January, 2020
Version
ZK 9.0.0

Overview

React is a JavaScript library for building user interfaces. We can use React as a front-end UI and use ZK as a pure backend. In this small talk, I will show you how to integrate React with ZK using the client binding API step by step.

For convenience, I use an open-source React demo project react-shopping-cart to demonstrate.

Load data from ZK

We need to create a View Model to use the client binding feature in React.

Create a ViewModel (VM) in ZK

We created an IndexVM.java and defined a property "products". The products property is loaded from a database.

IndexVM.java

@VariableResolver(DelegatingVariableResolver.class)
public class IndexVM {
	// omitted
	@WireVariable
	private ProductService productService;

	private List<ProductDto> products;
	// omitted
	@Init
	public void init() {
		products = productService.getProducts();
	}

	public List<ProductDto> getProducts() {
		return products;
	}
	// omitted
  • Line 11: We use Spring + Hibernate to communicate with the database. A service instance is needed to be injected in the VM by adding a @WireVariable annotation.
  • Line 14: Declare getter only here so ZK knows products is a readonly property of a VM.

Set Client Binding Annotations

In order to get the vm.products from the client, we need to add some annotation to the IndexVM.

IndexVM.java

@NotifyCommands({
	@NotifyCommand(value = "getProducts", onChange = "_vm_.products")
})
@ToServerCommand({"tipProducts", "placeOrder"})
@ToClientCommand({"getProducts"})
@VariableResolver(DelegatingVariableResolver.class)
public class IndexVM {
  // omitted
  • LIne 2: Add a @NotifyCommand and listen to _vm_.products changes (_vm_ means the VM object)
  • Line 5: Register a client command so the client can call getProducts. ZK client binding uses whitelist so no command is allowed to be called from the client by default.

Once we set, we can get the property from the client. Let's see how we get the products from ZK.

Use Client-Binding API in React

First, we need to use the ViewModel in zul, and create a root element for React.

index.zul

<zk xmlns:n="native">
    <div id="main" viewModel="@id('vm') @init('react.vm.IndexVM')">
        <n:div id="root"/>
    </div>
</zk>
  • Line 2: The id property is needed for client binding to get the correct VM.
  • Line 3: We have created a native DIV element for React to render.

We can use binder.after to get products from ZK.

zkbind.$('$main').after('getProducts', function (data) {
    // the data is vm.products
    // and this function will be called each time vm.products is changed
});

The react-shopping-cart loads JSON data a server. A method fetchProducts initiates axios.get to make an AJAX request.

react-shopping-cart/src/services/shelf/actions.js

export const fetchProducts = (filters, sortBy, callback) => dispatch => {
  return axios
    .get(productsAPI)
    .then(res => {
      let { products } = res.data;
// omitted

We can use client binding API to request with ZK instead. I wrote a utility class to handle it for convenience.

zkBinder.js

function getBinder(name) {
  return window.zkbind && window.zkbind.$(name);
}

export default {
  after(name, event, callback) {
    let binder = getBinder(name);
    if (binder) {
      binder.after(event, callback);
      return true;
    }
    return false;
  },
  // omitted

By default, ZK uses one-way binding, so the function is bound to the property. To simulate a one-time request, I need to trigger a command first, the command just notifies ZK that it changes (but actually not) in order to trigger @NotifyCommand


react-shopping-cart/src/services/shelf/actions.js

export const fetchProducts = (filters, sortBy, callback) => dispatch => {
  return axios
    .get(productsAPI)
    .then(res => {
      let { products } = res.data;
// omitted

Submit data to ZK

Download the Source

You can access the complete source at github.

Other Front-End Frameworks Integrations

  • Angular
  • Vue.js


Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.