65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ASP.NET AJAX 和 Web 服务实现闪电般的行内编辑(架构与自定义)- 第二部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (13投票s)

2007年11月2日

CPOL

7分钟阅读

viewsIcon

70026

downloadIcon

1339

用于网格行内编辑的 JavaScript+AJAX 解决方案。

在此处 阅读第一部分 Screenshot - grid.gif

文章的第一部分中,我展示了如何使用 IEC(行内编辑控制器)在网格中启用行内编辑。我们在一个实际项目中使用了这种行内编辑 - TargetProcess - 基于 ASP.NET 的敏捷项目管理软件。本部分将介绍架构和高级功能,如验证和扩展。

基本类

行内编辑解决方案包含三个类

  • InlineEditController - 处理行内编辑的控制器类
  • EditAreaSettings - 存储关于 IEC 应处理内容的类的类
  • TransactObject - 管理保存过程的辅助对象(它充当同步器,并在服务器端错误时恢复旧值,并确认保存正确)
var editAreasSettings = new Array();
var shipNameEditAreaSettings =
    new EditAreaSettings("ShipName","ShipNameIdPrefix",null, true);
editAreasSettings.push(shipNameEditAreaSettings);
var shipAddressAreaSettings = new EditAreaSettings("ShipAddress","ShipAddressIdPrefix");
editAreasSettings.push(shipAddressAreaSettings);
var shipRegionAreaSettings = new EditAreaSettings("ShipRegion","ShipRegionIdPrefix");
editAreasSettings.push(shipRegionAreaSettings);
var inlineEditController =
    new InlineEditController('gridID', editAreasSettings, onSaveEventHandler, true);

function onSaveEventHandler(retObj)
{
  var transactionObj = new TransactionObject(retObj.itemID, inlineEditController);
  transactionObj.onStatusSuccess =  onRequestComplete;
  transactionObj.onStatusError =  onRequestError;
  retObj.OrderID  = retObj.itemID;
  TargetProcess.DaoTraining.BusinessLogicLayer.OrderService.UpdateOrder(retObj,
                                     transactionObj.onSaveSuccess ,
                                     transactionObj.onSaveError)
}

让我们看看所有的类。

InlineEditController

处理行内编辑的控制器类。

 var inlineEditControllerObj = new InlineEditController
                        (gridID, editAreasSettings , onSaveEventHandler, isExplicitSave)

参数

  • gridID
    网格的 ID

  • editAreasSettings
    EditAreaSettings 对象的数组

  • isExplicitSave
    一个标志,指定当另一个行进入编辑状态时,处于编辑状态的行是否应被保存。例如,当用户单击另一行时,如果此标志设置为 true,则第一行将被保存。

  • OnSaveEventHandler
    保存事件调用时的回调函数

  • IEC 不知道如何保存项目,因此应提供保存过程(例如,它可以是 Web 服务调用)。

    function onSaveEventHandler(retObj){
         retObj.OrderID  = retObj.itemID;
         MyWebService.OrderService.UpdateItem(retOb);
    }
  • retObj
    包含已编辑值的对象

公共方法

  • inlineEditControllerObj.commitChanges(itemID)
    应调用此方法以确认数据已成功保存,无需恢复初始值。

  • inlineEditControllerObj.abandonChanges(itemID)
    在服务器端出错时,应调用此方法以恢复初始值。

EditAreaSettings

存储关于 IEC 应处理什么的类的类。IEC 需要有关应编辑什么以及如何编辑的信息。EditAreaSettings 对象包含编辑项目所需的所有基本信息。

 var editAreaSettingsObj  = new EditAreaSettings(areaName,
                        areaPrefix,
                        areaDataSourceControlID,
                        isFocus,
                        onSelectValue,
                        onExtractEditedValue,
                        onRenderEditedValue,
                        onCancelEditValue,
                        onEditValue)

参数

  • areaName
    将编辑后的值映射到 retObj(您还记得 retObj 已传递到 OnSaveEventHandler 并存储了所有需要保存的新值)。

  • areaPrefix
    我们使用此参数查找“编辑区域”。“编辑区域”的完整 ID 是 areaPrefix +“项目 ID”。

     <asp:TemplateField HeaderText="Ship Name">
               <ItemTemplate>
    
                     <span id="ShipNameIdPrefix<%# Eval("OrderID")%>">
                        <asp:Label ID="Label1" runat="server"
                             Text='<%#Eval("ShipName")%>'></asp:Label>
                     </span>
               </ItemTemplate>
     </asp:TemplateField>
    
         var shipNameEditAreaSettings = 
             new EditAreaSettings("ShipName","ShipNameIdPrefix",null, true);
         editAreasSettings.push(shipNameEditAreaSettings);
         var inlineEditController =
            new InlineEditController('uxGridID', editAreasSettings,
                onSaveEventHandler, true);
    ...
  • areaDataSourceControlID
    数据源控件的 ID

    当行为行启用编辑状态时,所有标签都将转换为可编辑状态。这意味着文本将被输入字段替换。另一种情况是,文本值应被预定义值的下拉框替换。IEC 将尝试根据列中的文本设置下拉框中的值。DataSourceControl 是一个包含所有必需值的下拉框。

  • isFocus
    当编辑状态激活时,“编辑区域”应获得焦点吗?

  • onSelectValue
    在大多数情况下,您将使用此处理程序在 DataSource 控件中设置正确的值。

  • onExtractEditedValue
    可以使用自定义处理程序从“编辑区域”提取已编辑的值。

  • onCancelEditValue
    可以使用自定义处理程序将编辑区域设置为原始(只读)状态。

  • onEditValue
    可以使用自定义处理程序将编辑区域设置为炫酷(行内编辑)状态。

  • OnRenderEditedValue
    可以使用自定义处理程序渲染具有特殊性的原始(只读)值,例如显示代表优先级或其他内容的图像。

所有这些处理程序都可以省略。您应该在复杂情况下使用它们。

TransactObject

管理保存过程的辅助对象(它充当同步器,并在服务器端错误时恢复旧值,并确认保存正确)。

var transactionObject  =  new TransactionObject(itemID, inlineEditController);

参数

  • itemID
    将要更新的项目 ID。
  • inlineEditController
    IEC 的引用。

IEC 生命周期

我应该说,IEC 的生命周期并不简单。很难用简短的语言描述它是如何工作的,但让我们试试。

第一阶段。IEC 初始化

IEC 通过整个网格将事件处理程序绑定到相应元素。我们只有三个处理程序:编辑、保存和取消。因此,将它们绑定到必需的控件。

function InlineEditController
    (gridID, editAreasSettings, onSaveEventHandler, isExplicitSave)
 {
   ...
   //******************** Fields ****************************
   var activeInlineEditPanel;
   var thisRefInlineEditController = this;
   //the object that stores the previous values of item,
   //used in case of calling abandonChanges(itemId)
   var previousStates  = new Object();
   attachEvents();
   function attachEvents()
   {
       var grid = document.getElementById(gridID);
       if(grid == null)
       {
           alert("error: Unable to find a grid.");
           return;
       }
       //assign the click handler to the grid(HTMLTable)
       grid.onclick = onGridClick;

       for(var index=0; index < grid.rows.length;index++)
       {
         var cells = grid.rows[index].cells;
         for(var index1=0; index1 < cells.length; index1++)
         {
              var element = findInlineEditPanelInElement(cells[index1]);
              if(element == null)
                 continue;
              if(element.attributes == null)
                 continue;
              //look up for "Inline Edit Panel"
              if(element.attributes[INLINE_PANEL_FLAG_ATTRIBUTE] != null)
              {
                 var row = findRowForElement(element);
                 row.ondblclick = onDblClickRow;
                 row.onkeypress = onEditing;
                 var children =  extractDHTMLElements(element);
                 for(var index2 = 0; index2 < children.length; index2++)
                 {
                      //look up for save, edit and cancel image buttons
                      var control = children[index2];
                      switch(control.attributes[INLINE_ACTION_ATTRIBUTE].nodeValue)
                      {
                         case INLINE_EDIT_ACTION:
                           control.onclick = onEditAction;
                         break;
                         case INLINE_SAVE_ACTION:
                           control.onclick = onSaveAction; 
            ...

第二阶段。启用编辑模式

当用户单击“编辑”链接时会发生什么?系统会不会像往常一样崩溃?这次不会!它将表格行设置为可编辑状态。最有趣的方法是 editRow(嗯,看起来它应该稍微重构一下,好的,我将为您留出一些改进的空间:)。那么它做了什么?

  1. 隐藏一些操作并显示行内编辑操作。
  2. 用漂亮的绿色突出显示可编辑行(嗯,如果您喜欢粉红色,也可以自定义)。
  3. 存储当前值(如果用户按下“取消”或出现服务器问题,我们以后可能需要它们)。
  4. 调用特定的 onEditValue 处理程序(如果存在)。
  5. 创建输入元素以允许用户实际编辑内容。
//********************* Events ************************
    ......
   //fires on edit image click
   function onEditAction()
   {   //suppose that some row can be in Edit State
       cancelEditRow();
       editRow(this.parentNode);
   }

   //fires on double click on row
   function onDblClickRow(eventObj)
   {
      if(eventObj == null)
         eventObj = event;
      var srcElement = eventObj.srcElement ? eventObj.srcElement : eventObj.target;
      if(srcElement.tagName == "A" )
        return;
      //look up for "inline edit panel"
      var inlineEditPanel = findInlineEditPanelInElement(this);
      if(inlineEditPanel)
      {
         cancelEditRow();
         editRow(inlineEditPanel);
      }
   }

   function editRow(inlineEditPanel)
   {
       if(activeInlineEditPanel != null)
       {
            alert("error: Unable to set edit state.
                  There must be no item in edit state.");
            return;
       }

       activeInlineEditPanel = inlineEditPanel;
       var children = extractDHTMLElements(activeInlineEditPanel);
       for(var index=0; index < children.length; index++)
       {
          var control = children[index];
          switch(control.attributes[INLINE_ACTION_ATTRIBUTE].nodeValue)
          {
             case INLINE_EDIT_ACTION: control.style.display='none'; break;
             case INLINE_SAVE_ACTION: control.style.display='';break;
             case INLINE_CANCEL_ACTION: control.style.display='';break;
             default:/* "Do nothing" */;
          }
       }

       highLightInlineEditRow(INLINE_ROW_BACKGROUNDCOLOR_ACTIVE);
       var itemID = getActiveInlineEditPanelID();
       if(itemID == null)
       {
           alert("error: Unable to find item id.");
           return;
       }
       // create a new object to store previuos values (just in the case)
       previousStates[itemID] = new Object();
       for(var index=0; index < editAreasSettings.length; index++)
       {
          var editAreaSettings = editAreasSettings[index];

         //get the Edit Area ID
          var editAreaID = editAreaSettings.areaPrefix+itemID
          var editArea = document.getElementById(editAreaID);
          if(editArea == null)
             continue;

          //saving particular value
          previousStates[itemID][editAreaID] = editArea.parentNode.innerHTML;
          //check if there is specific handler on edit event.
          if(editAreaSettings.onEditValue != null)
          {
               editAreaSettings.onEditValue(editAreaSettings, editArea);
          }
          //otherwise call predefined handler of IEC
          else
          {
             if(editAreaSettings.areaDataSourceControlID == null)
                 editTextField(editArea);
             else
                 editDataSourceField(editArea, editAreaSettings.areaDataSourceControlID);
          }
          //check if there is specific handler on select event.
          if(editAreaSettings.onSelectValue != null)
             editAreaSettings.onSelectValue(editAreaSettings, editArea);
          else
             //otherwise call predefined handler of IEC
             selectValueInDataSourceControl(editArea);

           if(editAreaSettings.isFocus)
             setFocusForEditableField(editArea);
       }
   }

在此阶段有两种可能的自定义选项

  • onEditValue
    可以使用自定义处理程序将编辑区域设置为炫酷(行内编辑)状态。示例

  • onSelectValue
    可以使用自定义处理程序在 DataSourceControl 中设置正确的值。示例

第三阶段。保存更改

首先,我们应该从表单字段中提取新值。名为 extractEditedValues extractEditedValue 的方法负责所有工作。结果是我们得到了一个包含所有新值的对象。然后,我们调用 onSaveEventHandler 将新值保存到数据库。

function onSaveAction()
   {
       var obj = extractEditedValues();
       //call the saving handler(the procedure that is defined outside of IEC)
       if(onSaveEventHandler != null)
       onSaveEventHandler(obj);
       //get row back into read state
       cancelEditRow();
   }

   function extractEditedValues()
   {
       if(activeInlineEditPanel == null)
          return null;
       var retObj = new Object();
       var itemID = getActiveInlineEditPanelID();
       if(itemID == null)
       {
           alert("error: Unable to find item id.");
           return;
       }
       retObj.itemID = itemID;
       for(var index=0; index < editAreasSettings.length; index++)
       {
            var editAreaSettings = editAreasSettings[index];
            var editArea = document.getElementById(editAreaSettings.areaPrefix+itemID);
            if(editArea == null)
               continue;
            //check if there is specific handler on extract data event.
            if(editAreaSettings.onExtractEditedValue != null)
                editAreaSettings.onExtractEditedValue
                (retObj, editAreaSettings, editArea);
            else
                //otherwise call predefined event of IEC
                extractEditedValue(retObj, editAreaSettings, editArea);
       }
       //return the obj that holds new edited values
       return retObj;
   }

  function extractEditedValue(refRetObj, editAreaSettings, editArea)
   {
          var children = extractDHTMLElements(editArea);
          if(editAreaSettings.areaDataSourceControlID == null)
          {  //save new value
             refRetObj[editAreaSettings.areaName] = children[1].value;
             //assign new value for readable field
             children[0].innerHTML = children[1].value;
          }
          else if(children[1].tagName == 'SELECT' )
          {
             var select = children[1];
             refRetObj[editAreaSettings.areaName] =
                   (trimText(select.options[select.selectedIndex].value)=="")
                   ? null : select.options[select.selectedIndex].value;
             children[0].innerHTML =
                   (trimText(select.options[select.selectedIndex].value)=="") ?
                    "" : select.options[select.selectedIndex].text;
         }
   }

在此阶段有一个可能的自定义选项。

onExtractEditedValue
可以使用自定义处理程序从“编辑区域”提取已编辑的值。示例

第四阶段。禁用编辑模式

当我们保存更改后,表格行应恢复到原始状态。实际上,这并非易事。cancelEditRow 函数负责转换。

function onEditing(eventObj)
   {
      if(eventObj == null)
         eventObj = event;
      //27 - key code of escape key
      if(eventObj.keyCode == 27)
        onCancelAction();
      ...

  }
   function onCancelAction()
   {
       cancelEditRow();
   }

 function cancelEditRow()
   {
       if(activeInlineEditPanel == null)
          return;

       var children = extractDHTMLElements(activeInlineEditPanel);
       for(var index=0; index < children.length; index++)
       {
          var control = children[index];
          switch(control.attributes[INLINE_ACTION_ATTRIBUTE].nodeValue)
          {
             case INLINE_EDIT_ACTION: control.style.display=''; break;
             case INLINE_SAVE_ACTION: control.style.display='none';break;
             case INLINE_CANCEL_ACTION: control.style.display='none';break;
             default:/* "Do nothing" */;
          }
       }

       highLightInlineEditRow(INLINE_ROW_BACKGROUNDCOLOR_NORMAL);
       var itemID = getActiveInlineEditPanelID();
       if(itemID == null)
       {
           alert("error: Unable to find item id.");
           activeInlineEditPanel = null;
           return;
       }
       for(var index=0; index < editAreasSettings.length; index++)
       {
          var editAreaSettings = editAreasSettings[index];
          var editArea = document.getElementById(editAreaSettings.areaPrefix+itemID);
          if(editArea == null)
             continue;

          if(editAreaSettings.onCancelEditValue != null)
          {
               editAreaSettings.onCancelEditValue(editAreaSettings, editArea);
          }
          else
            {
              if(editAreaSettings.areaDataSourceControlID == null)
                cancelEditTextField(editArea);
              else
                cancelEditDataSourceField(editArea);
            }

          if(editAreaSettings.onRenderEditedValue!=null)
              editAreaSettings.onRenderEditedValue(editAreaSettings, editArea);
       }
       activeInlineEditPanel = null;
   }

在此阶段有两种可能的自定义选项。

onCancelEditedValue
可以使用自定义处理程序将编辑区域设置为原始(只读)状态。示例

onRenderEditedValue
可以使用自定义处理程序渲染具有特殊性的原始(只读)标签,例如显示代表优先级或其他内容的图像。示例

TransactObject 实现

TransactObject 是一个辅助对象,用于管理保存过程(它充当同步器,并在服务器端错误时恢复旧值,并确认保存正确)。

IEC 在服务器仍在处理请求时,用新值替换可编辑字段中的文本。由于更新是异步的,因此存在 Web 服务异常同步问题。当对象无法保存并且我们收到异常时会发生什么?新值将被设置为行,但这些值不再正确。

另一个问题是 AJAX.NET 将 Web 服务的所有异常包装到 WebServerError 类中,无法获取有关哪个项目失败的信息。TransactionObject 处理了这些问题。它有一个 IEC 的引用,可以在出错时恢复初始值。IEC 在调用 commitChanges abandonChanges 方法之前一直保留项目的初始值。

function onSaveEventHandler(retObj)
{
   var transactionObj = new TransactionObject(retObj.itemID, inlineEditController);
   transactionObj.onStatusSuccess = onRequestComplete;
   transactionObj.onStatusError = onRequestError;
   retObj.OrderID  = retObj.itemID;
   TargetProcess.DaoTraining.BusinessLogicLayer.OrderService.UpdateOrder(retObj,
                                     transactionObj.onSaveSuccess ,
                                     transactionObj.onSaveError)
}

function TransactionObject(itemID, inlineEditController, onSuccessStatus, onErrorStatus)
{
  var thisRefTransactionObject = this;
  this.inlineEditController = inlineEditController;
  this.itemID = itemID;
  this.onStatusSuccess = onSuccessStatus;
  this.onStatusError = onErrorStatus;

  //--- Events ---
  this.onSaveSuccess = function(result)
  {
    //remove the initial values for item from IEC.
    thisRefTransactionObject.inlineEditController.commitChanges
          (thisRefTransactionObject.itemID);
    //call custom handler if such handler is provided
    if(thisRefTransactionObject.onStatusSuccess)
        thisRefTransactionObject.onStatusSuccess(result);

  }

  this.onSaveError = function(ex, context)
  {
     //restore the initial values for item
     thisRefTransactionObject.inlineEditController.abandonChanges
          (thisRefTransactionObject.itemID);
     if(thisRefTransactionObject.onStatusError)
        thisRefTransactionObject.onStatusError(ex);

  }

扩展基本功能。自定义编辑处理程序

默认情况下,IEC 具有简单的文本和下拉框编辑逻辑,因为不可能实现所有情况。

有时,您会遇到基本功能不够用的情况。例如,Order 类的 Priority 属性。当行处于只读状态时,它必须显示优先级图像,而在编辑状态时,它必须显示下拉框。

Screenshot - priority.jpg

   <asp:TemplateField>
          <ItemTemplate>
            <%--priorityname attribute holds priority value --%>
                <span priorityname='<%#Eval("Priority")%>'
                     id="PriorityIdPrefix<%# Eval("OrderID")%>">
                      <span>
                            <%#GetPriorityHTML(Container.DataItem)%>
                      </span>
                </span>
          </ItemTemplate>
   </asp:TemplateField>

var prioritySettings = new EditAreaSettings
                ("Priority","PriorityIdPrefix","uxPriorities");
prioritySettings.onRenderEditedValue = onRenderPriorityValue;
prioritySettings.onSelectValue = onSelectPriorityValue;
editAreasSettings.push(prioritySettings);
var inlineEditController = new InlineEditController
           ('<%=uxOrders.ClientID%>', editAreasSettings, onSaveEventHandler, true);
var  HIGHEST_PRIORITY_IMAGE =  "<%=HIGHEST_PRIORITY_IMAGE%>";
var  NORMAL_PRIORITY_IMAGE  =  "<%=NORMAL_PRIORITY_IMAGE %>";
var  LOWEST_PRIORITY_IMAGE  =  "<%=LOWEST_PRIORITY_IMAGE %>";
var  HIGHEST_PRIORITY = "<%=Priority.Highest %>";
var  NORMAL_PRIORITY  = "<%=Priority.Normal %>";
var  LOWEST_PRIORITY  = "<%=Priority.Lowest%>";
var  PRIORITY_ATTR  = "priorityname";

需要提供两个处理程序:onRenderPriorityValue onSelectPriorityValue

onSelectPriorityValue 处理程序仅在下拉框中选择预定义的值。

function onSelectPriorityValue(editAreaSettings, editArea)
{
   var dataSourceControl =
        document.getElementById(editAreaSettings.areaDataSourceControlID);
   dataSourceControl.value =  editArea.attributes[PRIORITY_ATTR].nodeValue;
}

onRenderPriorityValuePriority 值转换为特定图像。

function onRenderPriorityValue(editAreaSettings, editArea)
{
    var dataSourceControl =
        document.getElementById(editAreaSettings.areaDataSourceControlID);
    var children = extractDHTMLElements(editArea);
    var readField = children[0];
    switch(dataSourceControl.value)
    {
        case HIGHEST_PRIORITY:
            readField.innerHTML = HIGHEST_PRIORITY_IMAGE;
        break;
        case NORMAL_PRIORITY:
           readField.innerHTML =  NORMAL_PRIORITY_IMAGE;
        break;
        case LOWEST_PRIORITY:
           readField.innerHTML =  LOWEST_PRIORITY_IMAGE;
        default:/*Do nothing*/   
    }
    editArea.attributes[PRIORITY_ATTR].nodeValue = dataSourceControl.value;
}

这种情况相当独特。在大多数情况下,IEC 的基本逻辑将满足您的要求。例如,Order 类的 Country 属性工作得很好。

 <asp:TemplateField HeaderText="Ship Country">
  <ItemTemplate>
   <span id="ShipCountryIdPrefix<%# Eval("OrderID")%>">
    <asp:Label ID="Label1" runat="server" Text='<%#Eval("ShipCountry")%>'></asp:Label>
   </span>
  </ItemTemplate>
 </asp:TemplateField>

 .....

  <select style="display: none" id="uxCountries">
  <option>-- Select Country</option>
  <option value="USA">United States</option>
  <option value="Canada">Canada</option>
  <option value="Mexico">Mexico</option>
  <option value="Afghanistan">Afghanistan</option>
  <option value="Albania">Albania</option>
 ....
  
var shipCountrySettings  =
    new EditAreaSettings("ShipCountry","ShipCountryIdPrefix","uxCountries");
editAreasSettings.push(shipCountrySettings);

如您所见,没有自定义处理程序。您所要做的就是将 uxCountries ID 传递给 shipCountrySettings。IEC 将使用列中的文本成功选择下拉框中的值并呈现新值。

扩展基本功能。复选框处理程序

如果您的布尔值在网格中表示为复选框怎么办?让我们看看如何实现。

Screenshot - rush.jpg
 <asp:TemplateField HeaderText="Rush Order">
  <ItemTemplate>
       <span id="IsRushOrderIdPrefix<%#Eval("OrderID")%>" >
          <asp:CheckBox  Enabled="false" runat="server"
              Checked='<%#Eval("isRushOrder") %>' ID="uxRushOrder" />
       </span>
  </ItemTemplate>
 </asp:TemplateField>

var isRushOrderSettings = new EditAreaSettings("IsRushOrder","IsRushOrderIdPrefix");
 isRushOrderSettings.onEditValue = onEditRushValueHandler;
isRushOrderSettings.onExtractEditedValue = onExtractRushValueHandler;
isRushOrderSettings.onCancelEditValue = onCancelEditRushValueHandler;
editAreasSettings.push(isRushOrderSettings);

我需要创建三个自定义处理程序:onEditRushValueHandleronExtractRushValueHandleronCancelEditRushValueHandleronEditValue 仅启用复选框。

function onEditRushValueHandler(editAreaSettings, editArea)
{
    var isRushOrderSpan = getFirstDHTMLElement(editArea);
    isRushOrderSpan.disabled = false;
    var isRushOrderChk = getFirstDHTMLElement(isRushOrderSpan);
    isRushOrderChk.disabled = false;
}

onExtractRushValueHandler 从复选框获取新值并将其保存在 retObj 中(您还记得,它会传递到 onSaveEventHandler )。

function onExtractRushValueHandler(retObj, editAreaSettings, editArea)
{
    var isRushOrderChk = getFirstDHTMLElement(getFirstDHTMLElement(editArea));
    retObj[editAreaSettings.areaName] = isRushOrderChk.checked;
}

onCancelEditValue 禁用复选框。

function onCancelEditRushValueHandler(editAreaSettings, editArea)
{
    var isRushOrderSpan = getFirstDHTMLElement(editArea);
    isRushOrderSpan.disabled = true;
    var isRushOrderChk = getFirstDHTMLElement(isRushOrderSpan);
    isRushOrderChk.disabled = true;
}

这样,您就可以为任何情况创建自定义处理程序,即使是极其复杂的情况。

输入验证

在 JavaScript 中没有标准的输入验证解决方案(例如 ASP.NET 验证器),但您仍然可以使用充当验证器的处理程序。幸运的是,TransactObject 会在服务器端出错时恢复初始值,这可能是由无效输入引起的,但这还不够。我们需要为 Freight 属性实现额外的验证,该属性应为 Decimal 类型以验证输入。

   <asp:TemplateField HeaderText="Freight">
  <ItemTemplate>
   <span id="FreightIdPrefix<%# Eval("OrderID")%>">
        <asp:Label ID="Label1" runat="server" Text='<%#Eval("Freight")%>'></asp:Label>
   </span>
  </ItemTemplate>
 </asp:TemplateField>

 var freightSettings = new EditAreaSettings("Freight","FreightIdPrefix");
  freightSettings.onSelectValue = onSelectFreightValueHandler;
  editAreasSettings.push(freightSettings);

我们只需要实现一个处理程序 onSelectFreightValueHandler。此处理程序为 Freight 输入框分配验证处理程序,并且无法键入任何除了数字和小数分隔符以外的字符。

  function onSelectFreightValueHandler(editAreaSettings, editArea)
  {
   var children = extractDHTMLElements(editArea);
    //children[0] - readable field that gets invisible since the row is in editable state
    //children[1] - input field that gets added since the row is in editable state
 children[1].onkeypress = onKeyPressDecimalValueHandler;
  }

  function onKeyPressDecimalValueHandler(eventObj,obj)
  {
    var thisRef;
    if(obj == null)
      thisRef = this;
    else
      thisRef = obj;

    function isValidInput(key,value)
    {
        if(key == "." && value.indexOf(".")==-1)
          return true;
        if(isNaN(key))
           return false;
        else
           return true;
    }

    if(typeof event == "undefined")
    {
        var key =  String.fromCharCode(eventObj.charCode);
        if(eventObj.charCode == 0)
           return;
        if(!isValidInput(key, thisRef.value))
           eventObj.preventDefault();
    }
    else
    {
        var key =  String.fromCharCode(event.keyCode);
        if(!isValidInput(key, thisRef.value))
           event.returnValue = false;
    }
}

另一个解决方案是使用 TransactObject 作为验证器。例如,如果我尝试输入无效日期,TransactObject 会恢复初始值并显示错误消息。

Screenshot - dateInput.jpg

Screenshot - dateError.jpg

现在您可以在所有列表中无问题地使用行内编辑了。

© . All rights reserved.