Telerik blogs

This is the second in a series of blog posts on the new RadListView client-side databinding features. In the first post, we introduced you to the basics of HTML templates, binding expressions and the databinding model in RadListView. In this post, we will see how RadListView supports automatic (read codeless) databinding to web services and JSON feeds.

For a quick reference, here is a brief list of the sections in this blog post:

  1. Web Service Types And Requirements
  2. How Web Service Binding Works
  3. RadListView DataService Settings
  4. Supported HTTP Methods And Default Parameters
  5. Binding To ASMX Web Services
  6. Binding To WCF Services
  7. Binding To OData Services
  8. Binding To Any General JSON Feed

Web Service Types And Requirements

Now, this is not the first time we write client-side support for automatic web service binding. RadGrid, RadScheduler, RadComboBox, RadMenu, RadTreeView, RadNotification, RadRotator, RadTagCloud are only some of the more popular controls that can bind on the client-side if you have a web service to feed the data. With RadListView, we wanted to take the flexibility to the next level. We created a client-bound control that doesn't care what kind of web service you have at hand. ASMX, WCF, Page Methods, OData or another type - RadListView will chew the data no matter where it's coming from. The only requirement - respond in JSON or JSONP.

How Web Service Binding Works

To tell RadListView you have a web service to serve the data, you provide the location of the JSON service to RadListView as a value of the RadListViewClientSettings.DataBinding.DataService.Location property. Depending on your service, you may need to configure additional settings, but let's discuss these in a minute. When RadListView is initialized on the client, it checks if service Location is provided along with a client-side ItemTemplate. If both are present, the control initializes web service parameters and calls your service. Client-side databinding in RadListView is heavily jQuery-based. jQuery.ajax() is used to make a request to the web service and parse the result. If a JSON result is properly received back, the control takes the data from the response and databinds automatically.

This happens on initial load without any developer intervention. When, for any reason, RadListView requires rebinding, it fires its client-side OnCommand event. The OnCommand event is an extension point for the developer, where databinding can be altered or canceled altogether. Users of RadGrid and its client-side databinding capabilities will find themselves at home, as RadListView follows the same client-side databinding life cycle for consistency.

If you need to explicitly rebind RadListView, you call RadListView.rebind(). This, again, causes RadListView to fire its OnCommand client event and make a web service call to refresh the data. Note, that RadListView.rebind() and RadListView.dataBind() are similar in result, but completely different in inner working. rebind() will cause the control to make a web service call. If data is properly retrieved, dataBind() is called internally to actually perform the databinding if there is a valid data source. Additionally, rebind() is what you would call if you had server-side databinding and wanted to make RadListView postback and rebind on the server. dataBind() doesn't work with server-side databinding at all.

Any time RadListView is databinding, it fires its client-side OnDataBinding event. This is another extensibility point for the developer. When binding to web services, you can use this event to alter not only RadListView control settings, but also the AJAX parameters that will be used to make a service call. The OnCommand and OnDataBinding events together provide a mechanism for easily changing any detail around RadListView's databinding, making databinding a very flexible feature.

What we discussed so far can be generalized in a neat little state chart diagram, describing the client-side databinding life cycle in RadListView:

RadListView databinding life cycle flow chart

What does it tell us? We have provided 2 extension points - the OnCommand and DataBinding client events. Both can be canceled to prevent databinding or implement some custom binding programmatically. Both can be used for changing the binding parameters, though at a different level. After the DataBinding event, jQuery takes up and makes an AJAX call to the web service. After the AJAX request, databinding can potentially fail if there is something wrong with the response. If JSON data is properly received, actual databinding happends and list view items are re/created. Databinding finishes off with the DataBound event. You can use this event to manipulate the DOM at the earliest possible time after databinding.

An important note to make here: the above state chart diagram describes the databinding life cycle in RadListView when no data caching is enabled. RadListView additionally supports data caching when binding to web services. When data caching enters the game, RadListView can skip the path from jQuery.ajax() to JSON Response and go straight to databinding, if there is a matching cache entry for the current state of the list view. More on caching later.

RadListView DataService Settings

To enable automatic web service binding, RadListView provides a set of properties that control various aspects of the web service request. These settings are collectively placed under RadListView.ClientSettings.DataBinding.DataService:

RadListView data service properties

These may seem like a lot of properties to consider, but don't worry, a lot of databinding scenarios work with default values for most of these settings. Let's go over a couple of the more important ones. Obviously, Location is where you always start with. You need to set it to the URL of your web service. This URL can be relative or absolute, for local or remove web services, respectively. When working with method-based web services like ASMX, WCF services or page methods, DataPath specifies the name of the method that will be called to retrieve the data. DataPath is not required, though, you can, just the same append, the method name to the end of the URL specified in Location.

CountPath is an interesting story. Some services provide one method (or URI) for the data and another for the total row count. When binding to such, the DataPath property specifies the method name to call when total row count is required. DataPath is always appended to Location to form the final URL, so no absolute URLs here. Total row count is required when paging is enabled in RadListView, so depending on the web service, RadListView can retrieve the total count either from a field in the response coming from the main data request, or from a separate count request. If you are designing your web service yourself, I don't see a reason for using a separate count method and excessively require a second request. But when using a web service you cannot modify, and it requires a separate count request, the CountPath property enables RadListView to look for the total item count with an additional service call.

Supported HTTP Methods And Default Parameters

One of the most important properties when working with web services is HttpMethod. RadListView can request web services using both GET and POST HTTP methods. Choosing the right HTTP method is very important, because it determines every other detail around calling your web service. By default, RadListView makes POST requests to a service. Request parameters are sent as post data in the form of a JSON-encoded string. If you change this property to Get, RadListView starts making GET requests, where request parameters are sent as URL-encoded query string values appended to the service URL. Equivalently importantly, the HttpMethod determines the default values for many of the above listed properties. Following is a comparison table that lists the properties affected by HttpMethod and their default values depending on the selected HTTP method:

Setting Value when POST Value when GET
DataPropertyName "Data" "results"
CountPropertyName "Count" "__count"
FilterParameterName "filterExpression" "$filter"
FilterParameterType List OData
SortParameterName "sortExpression" "$orderby"
SortParameterType List OData
StartRowIndexParameterName "startRowIndex" "$skip"
MaximumRowsParameterName "maximumRows" "$top"

As you can see, web service parameters vary drastically depending on the selected HTTP method. Let's assume paging, sorting and filtering are all enabled in RadListView when databinding to web services. When using POST requests, RadListView will send the data in the following format:

{"startRowIndex":0,
"maximumRows":8,
"sortExpression":"ProductID",
"filterExpression":"CategoryId == 4"}

For an equivalent set of paging, sorting and filtering parameters, here is what query string value will RadGrid append to the web service URL, when making GET requests:

$skip=0&$top=8&$orderby=ProductID&$filter=CategoryId%20eq%204

Quite bit of a difference just changing the HttpMethod, right? People familiar with the OData protocol will immediately recognize the OData-specific URL parameter names. That's right, RadListView defaults to OData support when using HttpMethod="Get". That desn't, however, mean that no other GET-accessible (or RESTful) JSON services are supported. These are just defaults and everything is configurable.

Similar to the request parameters, RadListView expects the response in a different format, depending on the HTTP method used. With a POST request, the default expected JSON response is either:

{ Data: [], Count: 0 }

or

{ d: { Data: [], Count: 0 } }

where the Data field is an array containing the data items and Count is the total count. Count field can be missing and if you provide the DataPath property, RadListView will make a second request for the total row count.

When HttpMethod="Get", the default expected JSON response is:

{ d: { results: [], __count: 0 } }

As noted previously, this is what an OData service would return. The results contains the data items and __count specifies the total row count. __count may also be omitted, but the CountPath property does not work with GET requests. RadListView won't make a second request to get the total row count when HttpMethod="Get".

Binding To ASMX Web Services

Let's see some databinding scenarios in action. We've assembled all examples in a small test project you can download. The examples are rather trivial, but the idea is to get you going with the client-side databinding basics, not to come up with a full-fledged Twitter feed widget. We can do that later on.

Let's define a simple RadListView layout and bind it to an ASMX service:

RadListView simple definition

Our service definition is basic - a couple of methods to return some data and count:

Simple ASMX service definition

Running the page, we see a couple of boxes on the screen:

RadListView rendered on the page

We've just created our first automatically databound RadListView. How difficult was that?

Binding To WCF Services

Binding RadListView to a WCF service is no more different. Let's examine a simple WCF service that returns the same data as our previous ASMX service.

Simple WCF service definition

This time, we return the data and count in a single request. This means RadListView will require only the Location and DataPath properties and no CountPath:

RadListView markup for binding to WCF service

Running the page, we get the same set of square boxes rendered on page. They look ugly, I know, but we'll have plenty of talks on how to beautify your dynamically bound HTML, I promise.

By now, you get the idea. Default HTTP method for service requests is POST in RadListView. ASMX services, WCF services and ASP.NET Page Methods use POST requests, so no additional configuration required. All we need is Location, DataPath and optionally CountPath. In fact, we don't even use total row count in the examples in this blog post, but I showed you how you can configure RadListView to request it. In our next blog post in this series, we'll see how total row count can be used for paging along with a couple of other nice features.

Binding To OData Services

Let's try binding RadListView to an OData service now. There are a couple of publicly available OData services out on the web. Let's use the Customers table from the Northwind OData service available at odata.org. Apart from being a GET-accessible web service, this is also a remote web service. This means that we need to configure RadListView for JSONP binding. Let's keep the example simple again and bind only the CustomerID field:

RadListView markup for binding to OData service

Looking at the DataService settings, they tell us that we are using an OData service URL to access the Customers entity set. We have also specified that we need to make GET requests to acces the service and that we want to use JSONP for accessing the data. JSONP is a convenient way of accessing a JSON-formatted data feed on a remote host. The details are explained in any JSONP-related article out on the web.

Save, run and we get the ProductID data values rendered in our browser, coming fresh from odata.org:

RadListView markup for binding to OData service

Behind the scenes, RadListView uses jQuery to make a GET request to the web service, specifying it wants to use the JSONP format and passing the required callback parameter. Here is the actual URL that gets called:

http://services.odata.org/Northwind/Northwind.svc/Customers?$format=json&$callback=[...]&_=[...]

jQuery knows how to make a JSONP request, passing $callback required for the JSONP exchange protocol and a cache buster parameter with a single underscore in the name. The rest is just boring databinding details RadListView hides from you. Automatic databinding to OData is three properties away. How easier can this become?

Binding To Any General JSON Feed

A couple of times already I mentioned that every detail around the client-side databinding in RadListView is configurable. Let me prove my words and bind RadListView to a very generic JSON feed. This is neither ASMX, nor WCF, nor Page Methods, nor ODAta. This can be any general data feed that can respond in JSON (or JSONP for remote access). It can vary in supported HTTP methods, parameter names, or the JSON structure in the response. Let's create a quick and dirty JSON feed by simply implementing a generic HTTP handler in our test project:

Custom JSON feed implementation

Admittedly, this may not be the best way to create a JSON data feed, but it does the job. More interestingly, my JSON service does not follow any previously discussed convention for the JSON response. If I browse to the service URL, I get the following response:

Custom JSON feed response

The wrapper JSON object contains a field named Result. This object, in turn, holds the data array in a Data_Items field and the total row count in a Total_Item_Count field. To make RadListView properly bind to this feed, we need to specify a custom DataPropertyName and CountPropertyName in the markup:

RadListView markup for binding to custom JSON feed

Note the property nesting. I instruct RadListView to search for a nested object in the Result field of the JSON response, then find the data array under Data_Items in this nested object. RadListView can parse nested property names and search for the data and count at an arbitrary nesting depth. This makes it very flexible for binding to any general JSON feed no matter where in the response is the data or total count nested.

As implemented, the above HTTP handler will accept both GET and POST requests. This means I can leave the default POST HttpMethod in RadListView.

Running the page with the above defined RadListView, we get the same old numbered squares - an indicator that RadListView has successfully databound to our custom feed:

RadListView bound to a custom JSON feed as shown in the browser

With the flexible client-side databinding capabilities of RadListView, you are not restrained to strictly using enterprise-level web service standards like WCF, OData and the like. Twitter, YouTube, Facebook and myriads of other JSON service APIs out there are at your reach in no time.

In the previous blog post in the series, I promised to show you how you can define a client-side layout and bind to web services automatically without writing any javacript. In this blog post, we created 4 sample databinding scenarios, connected to 3 different local web services and 1 remote OData service, yet wrote 0 lines of javascript. How many lines of javascript does it usually take you to create even the simplest of client-bound UI? Zero is the exact amount it took me with RadListView. Download the sample application I worked on in this project and try it yourself.

In this blog post, we introduced you to the automatic web service databinding features RadListView provides out of the box for you. For the sake of keeping the examples simple, we can't claim we've shown you anything colossally eye-pleasing. In the next blog post in this series, we'll try to fix that up. Along with some proper looking, client-bound tables and lists, we'll dive deeper into some advanced databinding features in RadListView. Paging, sorting, filtering, and item selection are some of the topics that we'll cover.

In the mean time, share your opinion, message, praise or critique in the comments section below. Your feedback on what we've been working on for some time now is important for us. Are we on the right track? Do we make working with client-side data easier for you? Would you rather have us do something else to ease your client-side coding pains?

This stuff is all at your reach now with the Q1 2012 release of RadControls for ASP.NET AJAX. Check out the demos or download a trial to experience the power, flexibility and ease of use with one of the most complete UI component suites on the market.

Download the sample application accompanying this blog post


About the Author

Veli Pehlivanov

is a Technical Lead at one of Telerik’s ASP.NET AJAX teams, where he primarily works on RadGrid and a few other data- and input-centric controls, including RadListView, RadCalendar and RadInput. Veli's interests lie in the area of web development, C#, .NET, JavaScript and agile project management. He likes being on the cutting edge of technology and is keen on delivering efficient software and a greater value for the user.

Related Posts

Comments

Comments are disabled in preview mode.