Undoubtedly, data plays a core role in nearly every
application. One of the most noted features of MS AJAX is that applications
update the web page asynchronously with the data fetched from the server, such
as the client-side JavaScript can connect with web services directly. In early
times, in order to obtain data from inside web services to be supplied to
applications we have to first create a server-side application, such as a web
form, and achieve the communication with the web services letting the system
generate the necessary proxies. But now, with the client-side JavaScript libraries
of the MS AJAX framework, you can access your required web services directly
from the browser side. Further, this process can be surrogated by the
client-side data source controls implicit getting the required data and
transfer it to visual controls via data binding. This is so important that the
client can exchange data with the server without any intermediate ties, which
greatly simplifies the development.
From Figure 1 above, careful readers should have noticed a
component—Base Class Library (which
corresponds to the file PreviewScript.js) which is the core of ASP.NET AJAX Futures January CTP. This library consists of
the namespaces and classes shown in Figure 2.
Figure 2: The Base Class Library components

Seen from the above figure, all the client-side controls
bond to the database and those responsible for obtaining datasets from web
services are all defined inside namespace Sys.Preview.Data. All the stuffs
included in namespace Sys.Preview.Data are: IData, DataRowState, SortDirection,
ServiceType, DataColumn, DataRow, DataRowView, DataRowCollection, DataTable, DataView,
DataFilter, PropertyFilter, DataSource, XMLDataSource. OK let's study the most
important ones of them one by one.
DataSource control
You have to manage data in most of your web applications—I mean retrieving and displaying data to
users and saving them back to a database after modification. This is a common
task that we have to perform in almost every project, so ASP.NET abstract it as
a build-in object, DataSource. MS AJAX client side script library, as well as
ASP.NET, has the same concept of DataSource. Figure 3 shows the advanced data
binding controls in MS AJAX vs. their possible ADO.NET 2.0 counterparts.
Figure 3: The MS AJAX client-side DataSource-related
controls compared with their ADO.NET 2.0 counterparts
Author's Note:
In the new AJAX Futures CTP (January 2007), DataSet was deleted inexplicably
(I've fine combed all the related *.js files but only found DataSetConverter
supported in PreviewScript.js).
There are two kinds of DataSource in the AJAX Futures CTP:
·
Sys.Data.DataSource—represents
a tabular data structure such as the result of a query to the database, similar
to object SQLDataSource in ASP.NET 2.0. This control can be used as the client
side data source of ListView and ItemView
controls. You can load data from the server and save the changes back to the
server after the user modifies them.
·
Sys.Data.XMLDataSource—represents
a hierarchy data structure such as an XML file, similar to the XMLDataSource
object in ASP.NET 2.0. This control can be used as the client side data source
of XSLTView control. This is a read only data source that you can only read
data and show it to user but not save the modifications back to the server.
Note that in this series, we'll only explorer the former.
Since all the client-side advanced data binding controls are
included inside file PreviewScript.js, let me give another figure (Figure 4) to
describe the relationships between them although some of them are to be
observed later.
Figure 4: The hierarchical relations between the
controls we are interested in

The following Listing 1 is the prototypes and descriptors
defined inside the DataSource control:
Listing 1: Prototypes and descriptors defined
inside control DataSource
Sys.Preview.Data.DataSource.prototype</span> = {
_data: null,
_initialData: null,
_autoLoad: false,
_serviceURL: "",
_loadMethod: "",
_serviceType: Sys.Preview.Data.ServiceType.DataService,
_isReady: true,
_dataChangedDelegate: null,
_request: null,
_timeout: 0,
//……omitted
_onDataAvailable: Sys$Preview$Data$DataSource$_onDataAvailable,
get_data: Sys$Preview$Data$DataSource$get_data,
set_data: Sys$Preview$Data$DataSource$set_data,
get_initialData: Sys$Preview$Data$DataSource$get_initialData,
set_initialData: Sys$Preview$Data$DataSource$set_initialData,
get_isDirtyAndReady: Sys$Preview$Data$DataSource$get_isDirtyAndReady,
get_isReady: Sys$Preview$Data$DataSource$get_isReady,
_set_isReady: Sys$Preview$Data$DataSource$_set_isReady,
get_loadMethod: Sys$Preview$Data$DataSource$get_loadMethod,
set_loadMethod: Sys$Preview$Data$DataSource$set_loadMethod,
get_parameters: Sys$Preview$Data$DataSource$get_parameters,
get_serviceURL: Sys$Preview$Data$DataSource$get_serviceURL,
set_serviceURL: Sys$Preview$Data$DataSource$set_serviceURL,
get_serviceType: Sys$Preview$Data$DataSource$get_serviceType,
set_serviceType: Sys$Preview$Data$DataSource$set_serviceType,
get_rowCount: Sys$Preview$Data$DataSource$get_rowCount,
initialize: Sys$Preview$Data$DataSource$initialize,
onDataPropertyChanged: Sys$Preview$Data$DataSource$onDataPropertyChanged,
onRequestComplete: Sys$Preview$Data$DataSource$onRequestComplete,
onLoadComplete: Sys$Preview$Data$DataSource$onLoadComplete,
ready: Sys$Preview$Data$DataSource$ready,
load: Sys$Preview$Data$DataSource$load,
save: Sys$Preview$Data$DataSource$save
}
Sys.Preview.Data.DataSource.descriptor</span> = {
properties: [ { name: 'data', type: Object },
{ name: 'autoLoad', type: Boolean },
{ name: 'initialData', type: String },
{ name: 'isDirtyAndReady', type: Boolean, readOnly: true },
{ name: 'isReady', type: Boolean, readOnly: true },
{ name: 'loadMethod', type: String },
{ name: 'rowCount', type: Number, readOnly: true },
{ name: 'serviceURL', type: String },
{ name: 'parameters', type: Object, readOnly: true },
{ name: 'serviceType', type: Sys.Preview.Data.ServiceType } ],
methods: [ { name: 'load' },
{ name: 'save' } ],
events: [ { name: 'dataAvailable', readOnly: true } ]
}
Sys.Preview.Data.DataSource.registerClass('Sys.Preview.Data.DataSource', Sys.Component);
According to my analysis, all stuffs within the prototype
block can be used with JavaScript programming, while only those within the descriptor
block can be used in xml-script declarative programming (we mainly discuss this
approach).
Events defined in DataSource—dataAvailable
The only self-defined and most important event is dataAvailable. This event is triggered when data inside the DataSource control are loaded completely. We can grab a
typical case for this event from the example Tasklist shipped with MS AJAX, as
follows:
Listing 2: Typical usage for event dataAvailable inside
control DataSource
<components>
<dataSource id="listsDataSource" serviceURL="TaskListDataService.asmx" />
<dataSource id="itemsDataSource" serviceURL="TaskItemDataService.asmx">
<dataAvailable></span>
<invokeMethodAction target="listsDataSource" method="load" /></span>
</dataAvailable></span>
</dataSource>
Here, two DataSource controls are defined declaratively. When
the second DataSource itemsDataSource are loaded
completely, the load method of the first DataSource is
then invoked.
Methods self-defined (no including those
defined in the parent) in DataSource
Method name
|
Description
|
load
|
Retrieves data from server—explicitly
submit queries to the server side according to the profile of current
DataSource.
|
save
|
Explicitly writes or updates data to the server side
according to the profile of current DataSource, i.e. saves client side
changes back to server.
|
Here's the definition for method save
of control DataSource in file PreviewScript.js:
Listing 3
function Sys $Preview $Data $DataSource $save()
{
//……omitted
if (this._serviceType == = Sys.Preview.Data.ServiceType.DataService)
{
var method = "SaveData";
var params =
{
changeList: changes, parameters: this._parameters, loadMethod:
this._loadMethod
};
var onComplete = Function.createDelegate(this, this.onLoadComplete);
var onError = Function.createDelegate(this, this.ready);
this._request = Sys.Net.WebServiceProxy.invoke(this._serviceURL, method,
false, params, onComplete, onError, this, this._timeout);
}
else
{
throw Error.createError("Save is not supported in Handler mode.");
}
}
Obviously seen from the code above, only when the type of property
serviceType is set to type DataService
can method save be available. This is of great
importance when we define web services to be consumed from the client side
later. And as for the mysterious method—SaveData, we'll discuss it in Part 2.
Properties defined in DataSource
Property name
|
Description
|
autoLoad
|
Boolean value indicating whether this data source control
will load data automatically from server after initializing. You should use InitialData
instead of using this property if you want to load the data with the page
loads, for it needs an extra round to serve right after the page loads.
|
initialData
|
Initial data that comes with the page. If there should be
some initial data on your page when a user hits the page for the first time,
for example, the first page of records of your list. Then we can use an Atlas
server side control InitialData to send the data with the page source, to
avoid querying the server again right after page loads.
|
isDirtyAndReady
|
Indicates whether this DataSource finished loading data
and the data is not empty and the data is not changed.
|
loadMethod
|
Another mysterious method to be discussed in relation to DataService in Part 2 of this series.
|
rowCount
|
Row count of the data.
|
serviceURL
|
URL of the Web Service where the DataSource can retrieve
data from. You should always set this property.
|
parameters
|
Parameters append to the service URL. Only used when
serviceType is set to Handler.
|
serviceType
|
Type of web service. Can be set to DataService
or Handler. Default and recommended value is DataService, which means your service is derived from Microsoft.Web.Services.DataService and has the build-in
supports for typical database CRUD operations.
|
Id (defined in parent)
|
Identifying the control.
|
data
|
The data retrieves from database and stores in the client
side.
Important note: this property can only be of type of Array or Sys.Preview.Data.DataTable.
|
isReady
|
Indicates whether this DataSource finished loading data
from server. You may bind this property to a data bind control’s enabled
property to disable the binding control when the data is in loading.
|
Next comes another DataSource related control—DataView.
DataView control
Generally, we can get data from server side and store them in
client side by using DataSource and then modify the
data we get on client side using DataTable (discussed later
on) object. However, sometimes we need to do some decorations before showing,
for example, we may need to page our data if it contains thousands of rows, or
our user may be only interested in some of the data. That’s the reason why the framework
has to introduce the DataView and DataFilter
objects.
Properties defined in DataView
Property name
|
Description
|
data
|
The actual data for decorating. You should always set a
DataTable get from DataSource control to this property to let the DataView
know the source data.
|
filteredData
|
The filtered data. Such as the paged data or the sorted
data.
|
filters
|
A collection of DataFilter objects to filter the data. You
can specify the DataView a collection of filters and they will be applied to
your data one by one. For more information about DataFilter object, please
see below.
|
hasNextPage
|
Whether there is a next page.
|
hasPreviousPage
|
Whether there is a previous page.
|
length
|
The number of rows in current page.
|
pageCount
|
The number of pages in current DataView.
|
pageIndex
|
Current page index.
|
pageSize
|
How many rows per page. You should set this property if
you need to page your data.
|
sortColumn
|
The column you want to sort the rows by. You should set
this property if you need the sort feature.
|
sortDirection
|
The directions you want to sort. Either Ascending (default
value) or Descending.
|
Notice that DataView object has only one self-defined method—sort. This method will
apply the sort operation according to sortColumn
property and sortDirection property. Also, you should remember
that you may need two additional controls in namespace Sys.Preview.UI.Data—DataNavigator and SortBehavior to help you with the paging and sorting issues. Here
for integrality, we also give a short introduction to the DataFilter
object.
Class Sys.Preview.Data.DataFilter is
designed as the abstract base class of all the filters. It provides an abstract
method filter for the derived class to implement its specified filter rules.
The Futures January CTP also provides one built-in filter—PropertyFilter,
which is used for filtering the items by one specified property and its value.
Author's Note: First, this DataView
control is quite different from that of ADO.NET 2.0. Second, since our samples
in this series are mainly using ListView and ItemView, you can get an example related to DataView from here.
And although this one is the former Atlas related, don't worry—you only need a slight modification with it according
to the new samples provided in this series.
DataTable control
Now comes another important control—DataTable, which implements the
Sys.Data.IData interface. By examining the source code of the samples shipped
with MS Ajax, we can easily find that many important controls, such as DataSource,
DataView, ItemView, and ListView all use the DataTable control to hold their
data. So, when you work with data binding in MS AJAX, you will regularly deal
with this control. And still for brevity, we just enumerate its events,
properties and methods.
Events defined in DataTable
Event name
|
Description
|
collectionChanged
|
Invoked when the row collection changes (such as adding,
deleting, and modifying).
|
propertyChanged
|
Invoked whenever one or more properties change. Also can
be used to trigger custom actions.
|
Properties defined in DataTable
Property name
|
Description
|
Notes
|
columns
|
Return an array of Sys.Preview.Data.DataColumn, similar to
the structure of a database table.
|
type: Array, readOnly: true
|
keyNames
|
Return an array of string(s) which describe(s) the key
column(s) in the DataTable
|
type: Array, readOnly: true
|
length
|
Return the total record numbers in the DataTable
|
type: Number, readOnly: true
|
isDirty
|
If the data in the DataTable has changed and not written
back to the database yet, then this property is set to true;
or else false.
|
type: Boolean, readOnly: true
|
Methods defined in DataTable
Method name
|
Description
|
remove(rowObject)
|
Delete the row associated with the passed row from current
DataTable.
|
get_length()
|
Return the total number of row data.
|
add(rowObject)
|
Append a new row at the end of current DataTable.
|
clear()
|
Delete all the row data in current DataTable.
|
createRow(initialData)
|
Create a new Sys.Preview.Data.DataRow according to the
current column structure.
|
getChanges()
|
Return the modifying operation with the DataTable, with
the returned value being one of the following kind of sets:
·
updated—the
newly-updated Sys.Preview.Data.DataRow;
·
inserted—the
newly-inserted Sys.Preview.Data.DataRow;
·
deleted—the
newly-deleted Sys.Preview.Data.DataRow.
|
getColumn(name)
|
Return an object DataColumn from the DataTable according
to the passed column name.
|
getRow(index)
|
Return an object DataRow according to the passed parameter
index.
|
getItem(index)
|
Same as the method getRow(index)
|
Here, we still choose to cut a long story short, leaving the
examples telling you everything.
DataColumn control
The DataTable class contains a
collection of DataColumn objects and a collection of DataRow objects. Since the client-side DataColumn
and DataRow controls are designed to simulate their ADO.NET
2.0 counterparts—DataColumn
and DataRow, we can easily figure out their relations from
the foregoing Figure 3. Yes, quite similar to the database counterpart, the
DataColumn here also possesses the properties listed below.
Properties defined in DataColumn
Property name
|
Description
|
Notes
|
columnName
|
Returns a string containing the column name.
|
type: String
|
dataType
|
Returns a Sys.Type object describing the data type in this
column.
|
type: Sys.Type
|
defaultValue
|
Returns a default value in this column.
|
|
isKey
|
Is this column is the key field?—returns true if yes, or else false.
|
type: Boolean
|
readOnly
|
To decide whether the data in this column is read only—returns true if
yes, or else false.
|
type: Boolean
|
Note that the DataColumn control does not supply any events methods
and only provides a few property related get-and-set methods, such as get_columnName(), get_dataType(), get_defaultValue() etc. General speaking, only these
properties are enough for use in practical development.
DataRow control
As with the DataColumn control above,
the DataRow control only exposes three properties in its
descriptor block of its definition—only the three ones can be used in
xml-script declarative mode.
Properties exposed in the descriptor block of
DataColumn
Property name
|
Description
|
Notes
|
$isDirty
|
If the row data has changed and not written back to the server
side yet, then this property is set to true; or else false.
|
type: Boolean
|
$index
|
Returns the corresponding index value of this row in
current DataTable.
|
type: Number
|
$selected
|
Check whether this row in the current DataTable is in the selected
mode.
|
type: Boolean
|
Also, the DataRow control provides a few property related
get-and-set methods and support only one event—propertyChanged which will get fired when one of the above
properties is changed.
So much is for the discussion with controls in namespace Sys.Preview.Data. Now, let's continue to examine those inside
another namespace—Sys.Preview.UI.Data.