Skip to main content

Data model for trees

3 replies [Last post]
tborak
Offline
Joined: 2005-04-18
Points: 0

I am new to jMaki and am in the midst of prototyping to see if it is something we can use on our project. My focus is on using the widgets as JSP tags and populating them via a call to a bean method. I have gotten this to work for an accordion component, but the bean method would actually build the JSON string via a StringBuilder.

Now I want to replace the accordion with a tree component. Building a string became tedious very quick. It seemed ideal to take advantage of JSONObject, but I cannot get this to work.

Here is the method that builds my JSONObject:

public static JSONObject buildTreeData(AuthorizedTeams ateams)
throws JSONException {

JSONObject retValue = new JSONObject();
JSONObject root = new JSONObject();
root.put ("title", "Organizations");
root.put ("expanded", true);
JSONArray data = new JSONArray();

Team[] teams = ateams.getTeams();

for (int i=0; i<teams.length; i++) {
JSONObject teamObj = new JSONObject();
teamObj.put("title", teams[i].getTeamName());
teamObj.put("expanded", true);

JSONArray children = new JSONArray();

User[] teamUsers = teams[i].getMembers();
for (int j=0; j<teamUsers.length; j++) {
JSONObject childObj = new JSONObject();
childObj.put("title",teamUsers [j].getUserName());
children.put(childObj);
}
teamObj.put("children", children);
data.put(teamObj);
}
root.put ("children", data);
retValue.put ("root", root);

return retValue;
}

Here is the JSP snippet:

<jsp:useBean id="teams"
class="com.myapp.assignment.AuthorizedTeams"
scope="request"/>
<a:ajax name="dojo.tree" value="${teams.teamsData}"/>

Here is the resulting HTML:

jmaki.addWidget({widgetDir:'http://localhost:8080/WGMPrototype/resources/dojo/tree',value:{"root":{"title":"Organizations","expanded":true,"children":[{"title":"Team A","expanded":true,"children":[{"title":"tborak"}]}]}},script:'http://localhost:8080/WGMPrototype/resources/dojo/tree/component.js',uuid:'dojo_tree4',name:'dojo.tree'});
(Has all the correct data)
No tree is ever displayed on the page. Instead, I get this error:

Unable to create an instance of jmaki.widgets.dojo.tree.Widget. See the error log for more detials.

I can't find any error log (I am using GlassFish through NetBeans 5.5 - no error in server log).

From the forum, I know people are getting tree components to work, so I am doing something fundamentally wrong...just not sure what it is.

Thanks for the help.

P.S. Just to explain: AutorizedTeams just holds a Team[]; Team holds a team name and User[]; User holds a user name.

The code that built the accordion String is:

public static String buildAccordionData(AuthorizedTeams ateams) {
StringBuilder teamsArr = new StringBuilder("[");

Team[] teams = ateams.getTeams();

for (int i=0; i<teams.length; i++) {
if (i > 0) {
teamsArr.append(",");
}
StringBuilder row = new StringBuilder();
row.append("{label:'" + teams[i].getTeamName() + "',");
User[] teamUsers = teams[i].getMembers();

StringBuilder buffer = new StringBuilder();
for (int j=0; j<teamUsers.length; j++) {
if (j > 0) {
buffer.append("<br/>");
}
buffer.append(ateams.buildUserLink(teamUsers[j].getUserName()));
}
row.append("content:'" + buffer.toString() + "'}");
teamsArr.append(row);
}
teamsArr.append("]");
return teamsArr.toString();
}

Note that this method returns a String, and the tree-building method returns a JSONObject. Is that significant? I modified the tree code to return a String (used toString method on JSONObject), with no luck.

Message was edited by: tborak

Message was edited by: tborak

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
tborak
Offline
Joined: 2005-04-18
Points: 0

Greg,

Thanks for the reply (and at such an odd hour). I must say, the support provided by the entire jMaki team is incredible. There truly is a strong devotion to the project, and it is appreciated by all developers using jMaki.

The code you provided is awesome. Also, the explanation sets things straight as to why JSONObjects were not working for me. Now I can continue to dynamically build my JSON strings in a manner that makes sense to me (using JSONObject and JSONArray). Needless to say, the code worked. Oddly enough, I was still getting the: [b]Unable to create an instance of jmaki.widgets.dojo.tree.Widget. See the error log for more details.[/b] error. It turns out that the prototype I am working on was initially developed on an older jMaki release, and it seems the libraries for the Dojo tree were missing according to http://forums.java.net/jive/thread.jspa?messageID=215455 (I did update the jMaki version for my NetBeans project - nice feature). Anyway, I re-dragged a tree to my JSP, and all worked well.

Thanks again for the help.

- Tom

gmurray71
Offline
Joined: 2003-07-31
Points: 0

Hi,

The key problem you are having has to do with the fact that if you are generating the content using the value object you need to use an object literal (a inline JavaScript object). The following would work:

value="{root:{title:'Organizations',
expanded:true,children:[
{title:'Team A',expanded:true,
children:[{title:'tborak'}]}]}}"/>

The code caused errors in the JavaScript of the page (Firebug found these pretty fast).

If you used the service attribute for pulling in the data you can have it in JSON format.

The key problem is that the JSON parser doesn't allow you to create object literals (but only JSON Ojbects. By default these contain key : value pairs where the keys are enclosed in double quotes which cause an error in the page).

I have written the following code to convert a JSONObject or JSONArray to an object literal. It is here:

/**
* Converts a JSON Object to an Object Literal
*
*/
public String jsonToObjectLibertal(JSONObject jo, StringBuffer buff) throws JSONException {
if (buff == null) buff = new StringBuffer("{");
else buff.append("{");
JSONArray names = jo.names();
for (int l=0; (names != null) && l < names.length(); l++) {
String key = names.getString(l);
String value = null;
if (jo.optJSONObject(key) != null){
value = key + ":";
buff.append(value);
jsonToObjectLibertal(jo.optJSONObject(key), buff);
}else if (jo.optJSONArray(key) != null) {
value = key + ":";
buff.append(value);
jsonArrayToString(jo.optJSONArray(key), buff);
} else if (jo.optLong(key, -1) != -1) {
value = key + ":" + jo.get(key) + "";
buff.append(value);
} else if (jo.optDouble(key, -1) != -1) {
value = key + ":" + jo.get(key) + "";
buff.append(value);
} else if (jo.opt(key) != null) {
Object obj = jo.opt(key);
if (obj instanceof Boolean) {
value = key + ":" + jo.getBoolean(key) + "";
} else {
value = key + ":" + "'" + jo.get(key) + "'";
}
buff.append(value);
}
if (l < names.length() -1) buff.append(",");
}
buff.append("}");
return buff.toString();
}

public String jsonArrayToString(JSONArray ja, StringBuffer buff) throws JSONException {
if (buff == null) buff = new StringBuffer("[");
else buff.append("[");

for (int key=0; (ja != null) && key < ja.length(); key++) {
String value = null;
if (ja.optJSONObject(key) != null){
jsonToObjectLibertal(ja.optJSONObject(key), buff);
} else if (ja.optJSONArray(key) != null) {
jsonArrayToString(ja.optJSONArray(key), buff);
} else if (ja.optLong(key, -1) != -1) {
value = ja.get(key) + "";
buff.append(value);
} else if (ja.optDouble(key, -1) != -1) {
value = ja.get(key) + "";
buff.append(value);
} else if (ja.optBoolean(key)) {
value = ja.getBoolean(key) + "";
buff.append(value);
} else if (ja.opt(key) != null) {
Object obj = ja.opt(key);
if (obj instanceof Boolean) {
value = ja.getBoolean(key) + "";
} else {
value = "'" + ja.get(key) + "'";
}
buff.append(value);
}
if (key < ja.length() -1) buff.append(",");
}
buff.append("]");
return buff.toString();
}

This way you can still use the JSON APIs and output the correct content needed to be for the value attribute.

Please let us know if this does not work for you.

-Greg

gmurray71
Offline
Joined: 2003-07-31
Points: 0

Hi,

The key problem you are having has to do with the fact that if you are generating the content using the value object you need to use an object literal (a inline JavaScript object). The following would work:

value="{root:{title:'Organizations',
expanded:true,children:[
{title:'Team A',expanded:true,
children:[{title:'tborak'}]}]}}"/>

The code caused errors in the JavaScript of the page (Firebug found these pretty fast).

If you used the service attribute for pulling in the data you can have it in JSON format.

The key problem is that the JSON parser doesn't allow you to create object literals (but only JSON Ojbects. By default these contain key : value pairs where the keys are enclosed in double quotes which cause an error in the page).

I have written the following code to convert a JSONObject or JSONArray to an object literal. It is here:

/**
* Converts a JSON Object to an Object Literal
*
*/
public String jsonToObjectLibertal(JSONObject jo, StringBuffer buff) throws JSONException {
if (buff == null) buff = new StringBuffer("{");
else buff.append("{");
JSONArray names = jo.names();
for (int l=0; (names != null) && l < names.length(); l++) {
String key = names.getString(l);
String value = null;
if (jo.optJSONObject(key) != null){
value = key + ":";
buff.append(value);
jsonToObjectLibertal(jo.optJSONObject(key), buff);
}else if (jo.optJSONArray(key) != null) {
value = key + ":";
buff.append(value);
jsonArrayToString(jo.optJSONArray(key), buff);
} else if (jo.optLong(key, -1) != -1) {
value = key + ":" + jo.get(key) + "";
buff.append(value);
} else if (jo.optDouble(key, -1) != -1) {
value = key + ":" + jo.get(key) + "";
buff.append(value);
} else if (jo.opt(key) != null) {
Object obj = jo.opt(key);
if (obj instanceof Boolean) {
value = key + ":" + jo.getBoolean(key) + "";
} else {
value = key + ":" + "'" + jo.get(key) + "'";
}
buff.append(value);
}
if (l < names.length() -1) buff.append(",");
}
buff.append("}");
return buff.toString();
}

/**
Convert a JSON Array to an Object literal
*/
public String jsonArrayToString(JSONArray ja, StringBuffer buff) throws JSONException {
if (buff == null) buff = new StringBuffer("[");
else buff.append("[");

for (int key=0; (ja != null) && key < ja.length(); key++) {
String value = null;
if (ja.optJSONObject(key) != null){
jsonToObjectLibertal(ja.optJSONObject(key), buff);
} else if (ja.optJSONArray(key) != null) {
jsonArrayToString(ja.optJSONArray(key), buff);
} else if (ja.optLong(key, -1) != -1) {
value = ja.get(key) + "";
buff.append(value);
} else if (ja.optDouble(key, -1) != -1) {
value = ja.get(key) + "";
buff.append(value);
} else if (ja.optBoolean(key)) {
value = ja.getBoolean(key) + "";
buff.append(value);
} else if (ja.opt(key) != null) {
Object obj = ja.opt(key);
if (obj instanceof Boolean) {
value = ja.getBoolean(key) + "";
} else {
value = "'" + ja.get(key) + "'";
}
buff.append(value);
}
if (key < ja.length() -1) buff.append(",");
}
buff.append("]");
return buff.toString();
}

This way you can still use the JSON APIs and output the correct content needed to be for the value attribute.

Please let us know if this does not work for you.

-Greg