Introduction

In the upcoming ZK8 release, there are many exciting new features, and among them is client side binding API (client binding for short). With client binding, we can not only trigger commands in the server side, but also register callbacks that may be invoked after executing server side commands. In other words, it is no longer necessary to compose a layout with ZK components in the server side. We now have the flexibility to integrate ZK with other front-end libraries.

For more detail, please look at our former blog post and small talk.

In this post, we will demonstrate how to integrate ZK8 server framework with React.js, a popular front-end library, as layout to build an online chat room.

Version: ZK8-RC

Demo

In this demo, we created a discussion channel for users to interact with each other simultaneously. We see from the video below that there are two windows where two concurrent users leave and receive messages.

Get Adobe Flash player

Implementation

It is quite simple to apply React.js as front-end while ZK as back-end service. We will focus on how to communicate and transfer data between server and client.

Let’s start with one part of our javascript file:

var CommentBox = React.createClass({
  loadCommentsFromServer: function() {
    var self = this;
    //once comments change, 
    //doCommentsChange will be invoked with comments as arguments
    zkbinder.after('doCommentsChange', function (evt) {
        self.setState({data: evt});
    });
    
  },
  handleCommentSubmit: function(comment) {
    var comments = this.state.data;
    comments.push(comment);
    this.setState({data: comments}, function() {
    	//invoke doAddComment to update comments
    	zkbinder.command('doAddComment', comment);
    });
  },
  getInitialState: function() {
    ...
  },
  componentDidMount: function() {
    ...
  },
  render: function() {
    ...
  }
});

It is a simple React component definition, and in line 6, we use ZK client binder to register a callback which will be called (executed) when data changes at server view model.

The process is as follows:

  • data change in server side
  • doCommentsChange is triggered
  • client binder receives the notification and triggers callback

Line 16 is also straightforward, we trigger the command in view model by ZK client binder to update data.

The following is a code snippet in view model:

        
    @Init
	public void init() {
		comments = new LinkedList();
		commentQueue.subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				if ("onAddComment".equals(event.getName())) {
					Map<String, Object> param = new HashMap<String, Object>();
					param.put("comment", event.getData());
					//trigger all instances to update comments
					BindUtils.
                    postGlobalCommand(null, null, "refreshComments", param);
				}
			}
		});
	}
	
	@GlobalCommand
	@NotifyChange("comments")
	public void refreshComments(@BindingParam("comment") Comment comment) {
		//sync comments with other instances
		if (!comments.contains(comment))
			comments.add(comment);
	}
	
	@Command
	@NotifyChange("comments")
	public void doAddComment(@BindingParam("author") String author, 
                                 @BindingParam("text") String text) {
		Comment c = new Comment(author, text);
		comments.add(c);
		commentQueue.publish(new Event("onAddComment", null, c));
	}	

 

We use ZK Event Queue to achieve real-time interaction. In line 10 and 11, we have to subscribe an event in order to receive it when it is published by line 31, and notify all view model instances to update their own data. That is what line 19 does.

You may notice that there is no method definition of doCommentsChange. Because the only purpose of doCommentsChange is to notify client the data has been changed, we do not need to define corresponding method and we can simply declare some annotations at the top of class level like the following:

@NotifyCommand(value="doCommentsChange", onChange="_vm_.comments")
@ToClientCommand({"doAddComment", "doCommentsChange"})
@ToServerCommand({"doAddComment"})
public class ReactVM {
...

Line 1, once data has changed, trigger doCommentsChange command(which is non-existing method).
Line 2, invoke registered callback in client side after executing the commands.
Line 3, we can trigger server side commands in client side.

Download

The complete implementation of this demo can be found on GitHub.

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.

Leave a Reply