</button>
这些代码仅仅利用了记录集中移动记录的方法。移到第一条和最后一条记录实现想来相当容易。只需记住数据控件有一个Recordset属性,由于该属性是一个对象,所以有其自己的方法。因此,代码可以写为:
dsoData.recordset.MoveFirst()
以上代码只是简单地调用数据控件管理的记录集的MoveFirst方法。
移到上一条和下一条记录的代码看上去有一点技巧,但也很简单。
if (!dsoData.recordset.BOF)
dsoData.recordset.MovePrevious()
以上是向后移动记录的方法,只需在执行MovePrevious方法之前,判断一下记录集的BOF属性,以确定当前记录不在记录集的开始位置。
3. 表格绑定
表格绑定不同于单个记录绑定,因为不只是为对齐数据而使用表格。在表格绑定中把数据绑定到了TABLE元素,能够一次看到多条记录,如图10-9所示:
图10-9 表格绑定的界面
这甚至比单个记录绑定更容易,实现表格绑定需要使用表格的DATASRC属性,然后使用DATAFLD属性绑定表格元素。这样就将表格与数据控件绑定起来,每一个表格单元绑定到单独的字段。
然而,看一下能够被绑定的HTML元素的列表,会发现表格单元元素(TD)并不在其中。因为这个原因,一般为只读的表格使用SPAN或DIV标记,而对于可编辑的表格则使用INPUT标记。例如,图10-9中的表格是用下列代码创建的:
<TABLE ID="tblData" DATASRC="#dsoData">
<THEAD>
<TR>
<TD>au_id</TD>
<TD>au_fname</TD>
<TD>au_lname</TD>
<TD>phone</TD>
<TD>address</TD>
<TD>city</TD>
<TD>state</TD>
<TD>zip</TD>
<TD>contract</TD>
</TR>
</THEAD>
<TBODY>
<TR>
<TD><INPUT TYPE="TEXT" DATAFLD="au_id"></INPUT></TD>
<TD><INPUT TYPE="TEXT" DATAFLD="au_fname"></INPUT></TD>
<TD><INPUT TYPE="TEXT" DATAFLD="au_lname"></INPUT></TD>
<TD><INPUT TYPE="TEXT" DATAFLD="phone"></INPUT></TD>
<TD><INPUT TYPE="TEXT" DATAFLD="address"></INPUT></TD>
<TD><INPUT TYPE="TEXT" DATAFLD="city"></INPUT></TD>
<TD><INPUT TYPE="TEXT" DATAFLD="state"></INPUT></TD>
<TD><INPUT TYPE="TEXT" DATAFLD="zip"></INPUT></TD>
<TD><INPUT TYPE="TEXT" DATAFLD="contract"></INPUT></TD>
</TR>
</TBODY>
</TABLE>
TABLE元素还有另外一个用于数据绑定的属性:DATAPAGESIZE,决定了在表格中可以显示的记录数。
<TABLE ID="tblData" DATASRC="#dsoData" DATAPAGESIZE="10">
在上面的例子中,表格一次只能含有10条记录。记录集的移动方法在这里不起作用,因为表格限制了可见的记录,所以必须使用表格的两个方法,如下所示:
<button id="cmdPreviousPage" title="Previous Page"
onclick="tblData.PreviousPage()">Previous Page</button>
<button id="cmdNextPage" title="Next Page"
onclick="tblData.NextPage()">Next Page</button>
4. 动态绑定
到目前为止,所有的例子都只显示了一个固定的记录集,绑定的字段在设计期间已经创建。但看起来大量的代码不能重用,特别是在Web应用程序正给用户带来越来越强的功能的情况下,这种方式缺乏开发程序的灵活性。
解决这个难题的方法是根据数据控件中的数据动态创建表中的字段。实际上这也比较容易,依赖于客户端的脚本程序。那么,假定让用户在表authors和publishers中进行选择,如图10-10所示:
图10-10 使用RDS动态数据绑定的界面
现在我们并不真想绑定两个表的所有字段,因为这会变得难以维护。如果源数据的结构改变了,或者想增加另一个表,情况将会怎样?处理这种情况的方法就是创建一个虚表,在运行期间动态地创建和绑定字段。
首先,创建数据控件。
<OBJECT CLASSID="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
ID="dsoData" HEIGHT="0" WIDTH="0"
ondatasetcomplete="createCells()">
</OBJECT>
这是RDS数据控件,与前面例子唯一不同的是这里没有设置参数,代码中也是如此。唯一增加的是设置了一个在数据控件读完数据后运行的函数。
接下来,需要创建两个按钮来确定数据。
<BUTTON ID="cmdAuthors"
onclick="resetData('authors')">authors</BUTTON>
<BUTTON ID="cmdPublishers"
onclick="resetData('publishers')">publishers</BUTTON>
下面创建虚表。
<TABLE ID="tblData" border=1>
<THEAD><TR></TR></THEAD>
<TBODY><TR></TR></TBODY>
</TABLE>
这充当了模板的作用。注意,表格中还没有单元格。这是因为并不知道数据有多少个字段,所以也将在运行期间创建它们。
现在编写JScript代码。首先看一下resetData函数,该函数设置数据控件的属性并加载数据。
function resetData(sTable)
{
// reset the data
dsoData.Connect = 'Provider=SQLOLEDB; Data Source=' +
'<%= Request.ServerVariables("SERVER_NAME") %>' +
'; Initial Catalog=pubs; User ID=sa; Password=';
dsoData.Server = 'http://<%= Request.ServerVariables("SERVER_NAME") %>';
dsoData.SQL = 'SELECT * FROM ' + sTable;
dsoData.Refresh();
}
虽然这看起来比使用参数更复杂一些,但是仍然比较简单。别忘了参数名是如何映射到属性的?这里所做的就是设置那些属性,然后调用Refresh方法更新数据控件。看上去,这可能比以前的例子更糟糕,因为在代码中只有不多的ASP,也只是简单地在属性中填入Web服务器的名字。但使用该方法可以在不修改代码的情况下将此ASP页面从一个服务器移到另一个服务器。作为数据源的表名可以通过选择适当的按钮而传给函数。
一旦加载了数据,将触发数据控件的ondatasetcomplete事件,运行createCells函数。
function createCells()
{
var fldF;
var tblCell;
// delete what's there already
deleteCells();
// now create the new cells
for (fldF = new Enumerator(dsoData.recordset.Fields);
!fldF.atEnd(); fldF.moveNext())
{
// create a new cell for the heading
tblCell = tblData.rows[0].insertCell();
tblCell.innerHTML = '<B>' + fldF.item().name + '</B>';
// create a new cell for the body
tblCell = tblData.rows[1].insertCell();
tblCell.innerHTML = '<INPUT TYPE="TEXT" DATAFLD="' +
fldF.item().name + '"></INPUT>';
}
// now bind to the data source
tblData.dataSrc = '#dsoData';
}
这同样也很简单。首先删除了现有的表格单元格(马上会介绍这个函数),然后遍历记录集的字段。在行头为每个字段创建一个新单元格(这个表格只有两行:第一行,即第0行,是表头;第二行,即第1行,是表体)。表格单元创建完后,将innerHTML属性设为对应的字段名。在表体中创建新单元格的过程类似,但此时使用innerHTML元件保存绑定到数据字段的INPUT标记。当所有的字段都完成这样的操作后,这个表就与数据控件绑定了。
因为这个页面允许在两个不同的数据集之间进行切换,所以需要先删除现有的数据。
function deleteCells()
{
var iCell;
var iCells;
// unbind the table
tblData.dataSrc = '';
// delete existing cells
iCells = tblData.rows[0].cells.length
for (iCell = 0; iCell < iCells; ++iCell)
{
tblData.rows[0].deleteCell();
tblData.rows[1].deleteCell();
}
}
这个子程序只是对表解除绑定,然后在表格中遍历所有的单元格并删除它们。等到上述程序执行完毕,表格就只剩下空的表头和表体行。
这是一个用RDS和一些DHTML实现的简单例子。可以容易地把其加到一个ASP包含文件中,并把该文件放到任何应用程序中,即使数据源不改变也可使用这种方法。
这个例子的全部代码——文件RDSDynamicBinding.asp以及类似的其他类型的数据控件例子,可以在Wrox站点上找到。
10.2.6 更新数据
迄今为止,仅学习了在客户端如何取到数据,但还没有涉及如何更新客户端数据,和将其送回服务器。别忘了,记录集是断开连接的,那么如何更新数据呢?对数据所做的任何修改只是数据控件中本地记录的一部分,因此为了更新服务器必须发一条特殊的指令。然而这并不需做什么复杂的工作,因为RDS数据控件有两个方法,允许我们要么取消最近对数据所做的任何修改,要么将所有修改送到服务器。
为了方便用户,可以为此创建一些按钮。
<BUTTON ID="cmdCancelAll" TITLE="Abandon All Chnages"
ONCLICK="dsoData.CnacelUpdate()">Cnacel</BUTTON>
<BUTTON ID="cmdUpdateAll" TITLE="Save All Changes"
ONCLICK="dsoData.SubmitChanges()">Save</BUTTON>
SubmitChanges方法只将那些改动过的记录送回服务器,而CancelUpdate方法则取消在本地记录集上所做的任何修改。
更新和取消更新操作并不是唯一所需的。如果想增加新的记录或删除一条现有的记录,怎么办?可以使用记录集的AddNew和Delete方法。这将增加或删除记录集中的记录,然后在发送SubmitChanges命令后,服务器上的数据就可以被更新。
<BUTTON ID="cmdDelete" TITLE="Delete This Record"
ONCLICK="dsoData.recordset.Delete()">Delete</BUTTON>
<BUTTON ID="cmdAddNew" TITLE="Add New Record"
ONCLICK="dsoData.recordset.AddNew()">Add</BUTTON>
……