Tutorial:Ext TreeLoader and Java (Legacy)

This version of our Learning Center is unmaintained.
This article may be out-of-date or contain incorrect information.
Please visit the new Sencha Learning Center for up-to-date material.

Go to the new Sencha Learning Center

From Sencha - Learn

Jump to: navigation, search
Summary: An example of Ext TreeLoader using Java HttpServlet as Server part, showing lazy loading approach used by TreeLoader
Author: Dmitry Popov (metpo@mail.ru)
Published: August 24, 2010
Ext Version: 3.2
Languages: en.png English

Contents

Introduction

Here I'll write a modification of this tutorial http://www.sencha.com/learn/Tutorial:Ext20_Tree_TreeLoader_PHP_MySQL under Java server part.

Defining tree data

Imagine a simple tree of musical instruments and brands within it. Here's the simple representation of a tree. Id's of the nodes are written in parenthesis.

Global root (0)
	Guitars (1)
		Acoustic (11)
			Taylor (110)
 			Martin (111)
			Alvarez Yairi (112)
		Electric (12)
 			Fender (120)
			Gibson (121)
		Semihollow (13)
	Violins (2)	

Note that original tree root with id = 0 (which is the only one) is defined by TreePanel's root config option, or set by it's setRootNode() method. But the original root could be easily hidden by setting TreePanel.rootVisible property to false. As a result, on the web-page we can see several top-level nodes (like "Guitars" and "Violins" in my case). These top-level nodes can, obviously, be leaves (nodes with no chilren) or roots (nodes with children).

Java classes

First, let us define a simple Java class for representing tree node for TreeLoader (see TreeLoader api doc).
Note that I used org.json.JSONObject, org.json.JSONException and org.json.JSONArray classes from org.json package for importing java primitives as well as arrays to JSON format. Sources of org.json package could be loaded from here: http://www.json.org/java/index.html
Node's leaf property is used for showing whether tree node is leaf node or not. It should be mentioned, that during lazy loading of a node, which is a parent node (though not a leaf), it's children should not be sent by server, instead of it, "leaf": false value displays to TreeLoader that it's not a leaf.
addChild(Node) method is not used in this sample (TreeServlet). This method is added for the purpose of eager (unlazy) loading of some expanded node. I mention great Ext realization of this: if, f.e., the guitars tree with all children hiearchy is returned from "node=0" request, then during expanding of "Guitars", "Acoustic", or "Electric" nodes no requests from TreeLoader are made (you can check this by adding children to guitars Node in TreeServlet expanding "Guitars" node at the web-page and watching System.out-s at server log). Also, after expanding node once in lazy-load mode, it's content is also saved and no consequent requests are sent to server after expanding this node again. Ext actually represents good code! :)

public class Node
{
	public Node(Integer id, String text) {
		this.id = id;
		this.text = text;
	}
 
	public JSONObject toJson() throws JSONException {
		JSONObject json = new JSONObject();
		json.put("id", id);
		json.put("text", text);
		json.put("leaf", leaf);
 
		if (children.isEmpty())
			return json;
 
		JSONArray jsonArray = new JSONArray();
		for (Node child : children)
			jsonArray.put(child.toJson());
 
		json.put("children", jsonArray);
		return json;
	}
	public void addChild(Node node) {
		leaf = false;
		children.add(node);
	}
 
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	public boolean isLeaf() {
		return leaf;
	}
	public void setLeaf(boolean leaf) {
		this.leaf = leaf;
	}
 
	private Integer id;
	private String text;
	private boolean leaf = true;
	private List<Node> children = new ArrayList<Node>();
}


Then, we'll define a HttpServlet serving POST responses from TreeLoader (remember that "url: contextPath + '/tree'" on Jsp-page?). At this simple article, I focus on responding to TreeLoader (sending JSON to it), so no database is present, servlet class generates data itself, according to node parameter of the servlet, sent by TreeLoader when expanding some tree node.
I emphasize, that JSON response to TreeLoader request must be an array, so it's not the one JSON object in curly braces {}, but JSON array, so it's always included in square brackets [], even if there's only one node at the current level of a tree. As you can see, I use JSONArray class for writing a response. It's toString() method nicely and easily converts Java representation to JSON format.
The main thing to note is that for lazy loading, for each node parameter value only the corresponding expaned node's children are returned. Also mention that for "Global root" (node = 0), 2 top-level nodes (Guitars and Violins) are returned. This call from TreeLoader after the loading of the web-page, before the user expands any node. So, after the page has loaded, we see "Guitars" expandable node and "Violins" leaf at the top level of our tree.

public class TreeServlet extends HttpServlet
{
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int node = Integer.parseInt(request.getParameter("node"));
		System.out.println("node: " + node); // just for debug purposes
 
		try
		{
			String jsonResult = createTree(node).toString();
			System.out.println("result: " + jsonResult); // just for debug purposes
			response.getOutputStream().write(jsonResult.getBytes());
		}
		catch (JSONException e)
		{
			throw new ServletException(e);
		}
	}
 
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response); // now you can see the results by typing request path in the browser
	}
 
 
	private JSONArray createTree(int node) throws JSONException {
		if (node == 0)
		{
			JSONArray array = new JSONArray();
			Node guitars = new Node(1, "Guitars");
			guitars.setLeaf(false);
			array.put(guitars.toJson());
 
			Node violins = new Node(2, "Violins");
			array.put(violins.toJson());
 
			return array;
		}
 
		if (node == 1)
		{
			JSONArray array = new JSONArray();
 
			Node acoustic = new Node(11, "Acoustic");
			acoustic.setLeaf(false);
			array.put(acoustic.toJson());
 
			Node electric = new Node(12, "Electric");
			electric.setLeaf(false);
			array.put(electric.toJson());
 
			Node semihollow = new Node(13, "Semihollow");
			array.put(semihollow.toJson());
 
			return array;
		}
 
		if (node == 11)
		{
			JSONArray array = new JSONArray();
 
			Node taylor = new Node(110, "Taylor");
			array.put(taylor.toJson());
 
			Node martin = new Node(111, "Martin");
			array.put(martin.toJson());
 
			Node alvarez = new Node(112, "Alvarez Yairi");
			array.put(alvarez.toJson());
 
			return array;
		}
 
		if (node == 12)
		{
			JSONArray array = new JSONArray();
 
			Node fender = new Node(120, "Fender");
			array.put(fender.toJson());
 
			Node gibson = new Node(121, "Gibson");
			array.put(gibson.toJson());
 
			return array;
		}
 
		return null;
	}
}

JSON results of TreeLoader requests

Now let's deploy our simple web-application to web-server and see what does TreeServlet return, depending on node parameter value. In this simple sample, I did not take care of work out incorrect node values, therefore servlet will fail on any incorrect node value, appropriate values are only 0, 1, 11 and 12. Let it be your simple task to handle other values nicely.
TreeServlet is mapped to /tree, so you can simply open url like <your context path>/tree?node=0 in your browser and see the result. For this purpose, I dummily overrode doGet() method in TreeServlet to calling doPost(). Hope you remember, that TreeLoader Ajax request is done using HTTP 'POST' method (by default). Also the response of the request is echoed to web-server's log by System.out, so you can see it when expanding the node on the page, too.
Here are the results, depending on node's value:

node = 0 (expanding 'Global root'):

[{"id":1,"text":"Guitars","leaf":false},{"id":2,"text":"Violins","leaf":true}]


node = 1 (expanding 'Guitars' node):

[{"id":11,"text":"Acoustic","leaf":false},{"id":12,"text":"Electric","leaf":false},{"id":13,"text":"Semihollow","leaf":true}]


node = 11 (expanding 'Acoustic' node):

[{"id":110,"text":"Taylor","leaf":true},{"id":111,"text":"Martin","leaf":true},{"id":112,"text":"Alvarez Yairi","leaf":true}]


node = 12 (expanding 'Electric' node):

[{"id":120,"text":"Fender","leaf":true},{"id":121,"text":"Gibson","leaf":true}]

JSP Page

Here's finally the JSP page. It's a very simple modification of layout.html from this PHP tutorial (my thanks to Philip Almeida). Remember to change your paths to extjs files appropriately.
Pay your attention to setting rootVisible: false and using <%=request.getContextPath()%> as a prefix for TreeLoader request url. "tree" is obviously mapping of TreeServlet in web.xml.
Also note that 'Global root' has id: '0'. That actually defines a first call to TreeSerlvet after page is loaded, with node=0 parameter.

<!-- Do NOT put any DOCTYPE here unless you want problems in IEs. -->
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<link rel="stylesheet" type="text/css" href="../extjs/resources/css/ext-all.css">
	<!-- Include here your own css files if you have them. -->
	<style type="text/css">
	</style>
 
	<script type="text/javascript" src="../extjs/adapter/ext/ext-base.js"></script>
	<script type="text/javascript" src="../extjs/ext-all-debug.js"></script>
	<!-- Include here your extended classes if you have some. -->
	<!-- Include here you application javascript file if you have it. -->
	<title>Tree loader sample</title>
</head>
<body>
<br/><br/>
<div id="guitarTree">&nbsp;</div>
 
<script type="text/javascript">
	Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';
 
	Ext.onReady(function() {
 
		// define a tree
		var contextPath = '<%=request.getContextPath()%>';
		var guitarTreeLoader = new Ext.tree.TreeLoader({
			url: contextPath + '/tree' // equivalent to dataUrl
		});
 
		var guitarTreePanel = new Ext.tree.TreePanel({
			title: 'My category tree',
			collapsible: false,
			animCollapse: false,
			border: true,
			id: 'guitarTree',
			el: 'guitarTree', // html element id
			autoScroll: true,
			animate: false,
			enableDD: true,
			containerScroll: true,
			height: 400,
			width: 300,
			loader: guitarTreeLoader,
			rootVisible: false // set for not displaying 'Global root';
		});
 
		// set the root node
		var guitarTreeRoot = new Ext.tree.AsyncTreeNode({
			text: 'Global root',
			draggable: false,
			id: '0' // id of the root node
		});
 
		// render the tree
		guitarTreePanel.setRootNode(guitarTreeRoot);
		guitarTreePanel.render();
	});
</script>
</body>
</html>

The end

Thanks for your attention and thanks to ExtJs developers for the wonderful framework. Any contributions, questions and corrections are welcome.

This page was last modified on 25 August 2010, at 13:37. This page has been accessed 19,172 times.