ViewPanel vs. Dijit.Tree part 2

In this article I will describe how I converted. We will concentrate on how to use a restService control and how to get the data needed to load the first categories in the tree.

This in This
viewpanel grid

In the previous part of the series I explained a bit about how to create a simple dijit.tree and how it works. Now in this part I will explain how I used the restservice component from the extLib to generate a JSON structure which is compatible with the dijit.tree.

note: for these series you will need a copy of the fakenames.nsf file.

For those who are not familiar with the RestService control from Extlib. This control gives you the ability to create fairly easy an restfull service. I contains lots of default service types but for this tutorial we are going to write the Get method ourselves.We start by placing the following control on our xpage.

<xe:restService id="restService">
</xe:restService>

Configure the rest control

When we open up the properties pane we will see that the control offers a great deal of properties. The first one we will look at is the pathInfo property.

pathinfo

This property will tell the service when it should be rendering. A rest service typicaly is accessed by an http get, post, put or delete call. Therefore it needs an url identifier. Lets say we named the xpage api.xsp. And we define /names/  as the pathInfo. This way we can access the restService with the following url

http://yourdomain/database.nsf/api.xsp/names/

Now lets try it. You will notice that the service returns an empty string page ( among some header information). This is ofcourse because we told the service when to render but we didn’t tell it what to render. For this series it is enough to add the code that should be used in the Get call.

In the properties list expand the following path basic / service.  There are lots of properties but for now the following are the most important.

Property Description
doGet SSJS code that is being executed when the user does a get on the rest service
contentDisposition content disposition header
contentType Defines how the response ( which you will receive from the service)  is being formatted. Aka: which headers are being send out

Lets fill the doGet method. Open up the SSJS editor of this property and add the following code:

if(!isCategory(context.getUrl())){
	return getCategories();
}else{
	return getCategoryContent(context.getUrl());
}

Now add a SSJS library to your application and add the following lines of code:

function isCategory(url:XSPUrl){
	return false;
}

function getCategories(url:XSPUrl){
	var v:NotesView = getPeopleView();
	var nav:NotesViewNavigator = v.createViewNav();
	nav.setCacheGuidance(25,NotesViewNavigator.VN_CACHEGUIDANCE_READALL);

	var entry:NotesViewEntry = nav.getFirst();
	var nEntry:NotesViewEntry = null;
	var list:org.json.simple.JSONArray = new org.json.simple.JSONArray();

	while(entry != null){
		nEntry = nav.getNextCategory();

		if(entry.isCategory()){
			var values = entry.getColumnValues();
			var json:org.json.simple.JSONObject = new org.json.simple.JSONObject();
			json.put("$ref",values.get(0));
			json.put("name",values.get(0));
			json.put("children",false);
			list.add(json);
		}

		try{
			entry.recycle();
		}catch(e){

		}
		entry = nEntry;
	}
	try{
		nav.recycle();
		v.recycle();
	}catch(e){

	}

	return list.toJSONString();
}

function getPeopleView(){
	var v:NotesView = database.getView("(CountPeople)");
	v.setAutoUpdate(false);
	return v;
}

As you can see this code is fairly easy. It first checks if the request made is a category only request (currently it defaults to true ). Next on it will retrieve all categories from the view on the first level. ( See fakenames.nsf for details of the view ). Last but not least add this library to your xPage.

When we visit http://yourdomain/database.nsf/api.xsp/names/ you will get a result which looks like like:

[{"name":"A","children":false,"$ref":"A"},{"name":"B","children":false,"$ref":"B"},{"name":"C","children":false,"$ref":"C"},{"name":"D","children":false,"$ref":"D"},{"name":"E","children":false,"$ref":"E"},{"name":"F","children":false,"$ref":"F"},{"name":"G","children":false,"$ref":"G"},{"name":"H","children":false,"$ref":"H"},{"name":"I","children":false,"$ref":"I"},{"name":"J","children":false,"$ref":"J"},{"name":"K","children":false,"$ref":"K"},{"name":"L","children":false,"$ref":"L"},{"name":"M","children":false,"$ref":"M"},{"name":"N","children":false,"$ref":"N"},{"name":"O","children":false,"$ref":"O"},{"name":"P","children":false,"$ref":"P"},{"name":"Q","children":false,"$ref":"Q"},{"name":"R","children":false,"$ref":"R"},{"name":"S","children":false,"$ref":"S"},{"name":"T","children":false,"$ref":"T"},{"name":"U","children":false,"$ref":"U"},{"name":"V","children":false,"$ref":"V"},{"name":"W","children":false,"$ref":"W"},{"name":"X","children":false,"$ref":"X"},{"name":"Y","children":false,"$ref":"Y"},{"name":"Z","children":false,"$ref":"Z"}]

Creating the dijit.tree

With this response we can start to customize the dijit control we saw in party 1. Open up the xPage where you pasted the dijit.tree code from part 1 on. Or create a new xPage with the code from part 1. We have to make the following adjustments to the code.

    dojo.addOnLoad(function() {

// Create a data store to retrieve data from
var store = new dojox.data.JsonRestStore({ target: "api.xsp/names/",labelAttribute:"name"});

// secondly we create a treeModel. A treemodel are the classes / datastructure 
// on which the tree is running
        var treeModel = new dijit.tree.ForestStoreModel({
            store: store,
            rootId: "undefined",
            rootLabel: "alphabet",
            childrenAttrs: ["children"]
        });

// Last but not least we create a new instance of our tree. 
        new dijit.Tree({
            model: treeModel
        },
        "treeOne");
    });

As you can see we replaced the store with an instance of JSONRestStore. Since we retrieve our data from a RestService we need to have a correct way to interact with it. A JSONRestStore retrieves its data a restfull way. This means it will read /api.xsp/names/ and when we click a node it will read /api.xsp/names/A till Z ( depends on the node ofcourse ).

Next we create a new TreeModel. In this model we define the rootId ( undefined since there is none..) and we set the default name of the root. The last attribute tells the tree at which attribute name in the JSON it should check for children.

This concludes the second part of this series. We have a nice little dijit tree which only shows the first categories as nodes. I showed you how to create a simple RestService using the RestService control and some lines of SSJS and how we can use this data to populate a dijit.tree.

In the next part I will explain how we can change the SSJS so it will retrieve leaves ( aka content of a category ) when the tree needs it and I will show you how to add lazy loading.

update: Changed code for the getCategories call . It should be isCategory = false 

3 thoughts on “ViewPanel vs. Dijit.Tree part 2”

  1. awesome!!

    I am looking forward to your next post

    in an existing application I would like to replace
    our custom solution based upon xml transformation
    with this approach.

    do you happen to know if I can expand
    the tree with and highlight an entry on load?

    Reply
  2. In fact you can. If you provide a query property to the model it will open that node. I will

    add this info to the next part or to the part after that.

    Reply
  3. I found quite some problems in DDE, any idea what can be the cause?:

    The unknown tag xe:customRestService cannot be used as a complex type.
    api.xsp
    fakenames.nsf/XPages
    line 22
    com.ibm.designer.domino.ide.resources.designerproblem

    The unknown tag xe:customRestService cannot be used as a complex type.
    api.xsp
    fakenames.nsf/XPages
    line 31
    com.ibm.designer.domino.ide.resources.designerproblem

    The import org.json cannot be resolved
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 16
    Java Problem

    The import org.json cannot be resolved
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 17
    Java Problem

    The import org.json cannot be resolved
    Store.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/dijit
    line 5
    Java Problem

    The import org.json cannot be resolved
    Tree.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/dijit
    line 5
    Java Problem

    The import org.json cannot be resolved
    TreeModel.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/dijit
    line 5
    Java Problem

    The import com.ibm.xsp.extlib.component.rest.CustomServiceBean cannot be resolved
    NamesRestService.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 7
    Java Problem

    The import com.ibm.xsp.extlib.component.rest.CustomService cannot be resolved
    NamesRestService.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 6
    Java Problem

    The hierarchy of the type XspTree is inconsistent
    XspTree.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/xsp/dijit
    line 12
    Java Problem

    JSONObject cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 38
    Java Problem

    JSONObject cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 38
    Java Problem

    JSONObject cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 65
    Java Problem

    JSONObject cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 65
    Java Problem

    JSONObject cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 100
    Java Problem

    JSONObject cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 100
    Java Problem

    JSONAware cannot be resolved to a type
    Store.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/dijit
    line 9
    Java Problem

    JSONAware cannot be resolved to a type
    Tree.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/dijit
    line 9
    Java Problem

    JSONAware cannot be resolved to a type
    TreeModel.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/dijit
    line 9
    Java Problem

    JSONArray cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 49
    Java Problem

    JSONArray cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 49
    Java Problem

    JSONArray cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 91
    Java Problem

    JSONArray cannot be resolved to a type
    RestServiceImpl.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 91
    Java Problem

    CustomServiceBean cannot be resolved to a type
    NamesRestService.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 9
    Java Problem

    CustomService cannot be resolved to a type
    NamesRestService.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/rest
    line 14
    Java Problem

    Type safety: The expression of type List needs unchecked conversion to conform to List<UIComponent>
    JSFUtil.java
    fakenames.nsf/Code/Java/eu/jeroensomhorst/utik
    line 95
    Java Problem

    Reply

Leave a Reply to Patrick Kwinten Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.