Introduction
Lazy loading of the content on a web page is basically deferring the load of the content until it is needed. We will try implementing this concept of Lazy content loading in a webpage through a jQuery plug-in called Dynatree.
Dynatree is an open source jQuery tree plug-in that allows to dynamically create an HTML tree view control using JavaScript. More details on this can be found at http://dynatree.googlecode.com.
We will implement the lazy loading of the branches through a REST service written using WCF. Data transfer of the tree nodes will be done through JSON.
I have selected REST services over the conventional webservice because; REST services are a better and simpler option to share the data. To implement REST services, .NET 3.5 has introduces webHttpBindings
in WCF. This binding helps to publish our normal WCF service as per the standard of REST.
What are REST Services?
REST stands for Representational State Transfer, this means that each unique URL represents some object. Any REST service can be accessed using the standard HTTP GET
or POST
request. REST services are lightweight as no extra XML markup is used for transfer and the results are easy to understand and human readable.
Output
Development Environment
- Framework: .NET 3.5
- Environment: VS 2008
- Language: C#
- jQuery Frameworkversion: v1.3.2
Prerequisite
- Basic knowledge of WCF
- Basic Knowledge of jQuery
Create Project
Create a new ASP.NET Web Application with name “LazyLoading
”.
Tree Node Class
Now we will define a class to store the node data, which will be used to pass the information from server to the client in the form of JSON.
Add a class in the project with name “TreeNode
”. The class will look like this:
public class TreeNode
{
public string title { get; set; }
public bool isFolder { get; set; }
public bool isLazy { get; set; }
public string key { get; set; }
}
AJAX Enabled WCF Service
Now we will add an AJAX-enabled WCF Service to the project with name TS.svc.
TS.svc will be the service file where we will be defining our methods which can be invoked from jQuery. In our case, we have only one method with name GetNode
which takes “key” parameters and generated nodes of the tree on the basis of the key and return the list of TreeNode
to the caller.
To get the list of Nodes, our client will make request to our REST service as follows:
- http://localhost:5678/TS.svc/GetNodes/1 - To load all the root nodes
- http://localhost:5678/TS.svc/GetNodes/11234 - To load the child nodes for the node having id as 11234
Code of our WCF Service is as follows:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TS
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "GetNodes/{key}",
BodyStyle = WebMessageBodyStyle.Bare)]
public List<TreeNode> GetNodes(string key)
{
Thread.Sleep(1000); List<TreeNode> collection = new List<TreeNode>();
string NodeTitle = string.Empty;
if (key.Equals("1"))
{
NodeTitle = "Root";
}
else
{
NodeTitle = string.Format("Child Key-{0}", key);
}
for (int i = 1; i <= new Random().Next(15); i++)
{
int rC = new Random().Next(3) + 1;
collection.Add(
new TreeNode()
{
isFolder = (i % rC != 0),
isLazy = (i % rC != 0),
key = string.Format
("{0}{1}", key, i),
title = string.Format("{0}-[{1}]",
NodeTitle, i)
}
);
}
return collection;
}
}
In the above code, you can find out some attributes used. Please find the details for each below:
AspNetCompatibilityRequirementsMode
: You can then add an explicit attribute to your implementation class to make the ASP.NET context available in your application:
ServiceContract
: Namespace for the service to be specified. We are using blank as it is a test service and does not contain any URI format.
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "GetNodes/{key}",
BodyStyle = WebMessageBodyStyle.Bare)]
In the GetNodes
method, we are decorating it with the WebInvoke
attribute to specify that the method will be accessed using a standard HTTP GET
request and the output of the method call is in the form of JSON. The UriTemplate
specifies the path and the format to access the service. UriTemplate
class helps us to define Uri formats strings and the template text in the Uri. In our case GetNodes/{key}
, where key will be dynamically replaced while calling the service.
In JSON, the bare formatting means generic JSON object without any additional content appended by the WCF. Following is the sample bare JSON generated by our GetNodes
method.
For our testing, we can access this by simply calling http://localhost:5678/TS.svc/GetNodes/1.
WCF Configuration
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="LazyLoading.TSAspNetAjaxBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="TimeTrakkerServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="LazyLoading.TS" behaviorConfiguration="TimeTrakkerServiceBehavior" >
<endpoint behaviorConfiguration="LazyLoading.TSAspNetAjaxBehavior"
binding="webHttpBinding" contract="LazyLoading.TS" />
</service>
</services>
</system.serviceModel>
For our REST service, we are using the binding as WebHttpBinding
as we need to configure our endpoint that is exposed through HTTP GET
request instead of conventional SOAP message. The rest of the configuration is straight forward.
Client Side Code
Include the jQuery framework and the dynatree plug-in in the page.
<link href="CSS/Jquery.css" rel="stylesheet" type="text/css" />
<script src="Script/jquery.js" type="text/javascript"></script>
<script src="Script/ui.core.js" type="text/javascript"></script>
<script language="jscript" src="Script/jquery.dynatree.js"
type="text/javascript"></script>
JavaScript
$("#tree").dynatree({
title: "Lazy Tree",
rootVisible: true,
fx: { height: "toggle", duration: 200 },
initAjax: {
url: "TS.svc/GetNodes/1"
},
Here we are passing the URL by providing the key as 1; this will load all the root nodes of our tree.
onActivate: function(dtnode) {
$("#echoActive").text(dtnode.data.title);
},
onActivate
function will help if we want to handle the click event an any node, for example we want to load something else on the basis of node click then this function can be used, we can get the current selected node id dtnode.data.key
and the title as dtnode.data.title
.
onLazyRead: function(dtnode) {
dtnode.appendAjax({
url: "TS.svc/GetNodes/" + dtnode.data.key
});
}
onLazyRead
will be fired if we click on any lazy node of the tree, here we are calling our GetNode
method by passing the key of the node.
Conclusion
This article is the ASP.NET implementation of jQuery dynatree plugin. As a web developer, many times we need to develop such trees where lazy loading for huge tree structure becomes necessary for performance reasons.