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 |
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.
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
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?
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.
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