ASP.NET:如何从javascript访问转发器生成的元素?

时间:2009-01-23 21:16:25

标签: asp.net ajax

我有一系列使用 asp:repeater 生成的行:

<asp:repeater ID="itemsRepeater" 
      OnItemDataBound="itemsRepeater_ItemDataBound" 
      runat="Server">
   <itemtemplate>
      <tr>
         <td>
            <asp:HyperLink ID="linkView" runat="server"
               Text="<%# GetItemText((Item)Container.DataItem) %>" 
               NavigateUrl="<%# GetViewItemUrl((Item)Container.DataItem) %>" />
         </td>
         <td>
            <asp:HyperLink ID="linkDelete" runat="server"
                Text="Delete"
                NavigateUrl="<%# GetDeleteUrl((ActionItem)Container.DataItem) %>" />
         </td>
      </tr>
   </itemtemplate>
</asp:repeater>

转发器创建一个HTML表,每行包含一个项目链接和(基本上)一个“删除”链接。上面简化的示例代码生成类似于以下的HTML:

<TR>
<TD>
   <A href="ViewItem.aspx?ItemGuid={19a149db-5675-4eee-835d-3d78372ca6f9}">
      AllisonAngle_SoccerGirl001.jpg
   </A>
</TD>
<TD>
   <A href="DeleteItem.aspx?ItemGuid={19a149db-5675-4eee-835d-3d78372ca6f9}">Delete</A>
</TD>
</TR>

现在一切正常,但我想将“删除”转换为客户端。我希望能够点击链接,它将在客户端javascript:

  • 提示警告“你确定......”
  • 让javascript发出server-hit以实际删除他们想要的项目
  • 从客户端DOM树中删除该项

所以有四个问题需要解决:

  1. 如何将javascript与客户端点击删除链接相关联。
  2. 如何知道用户点击的项目删除
  3. 防止回复
  4. 删除用户点击的行
  5. 这是我的问题。

    从这里开始,你会发现我试图解决它。不要将以下任何内容与任何可能接受的解决方案相关联。仅仅因为我在下面发布了代码,并不意味着任何有用的代码。并不意味着我在最佳解决方案的吐痰距离内。而且因为我无法做任何工作 - 它必定走错了路。


    我的尝试

    连接Javascript

    第一项任务是将删除链接HTML从以下内容转换为:

    <A href="DeleteItem.aspx?ItemGuid={19a149db-5675-4eee-835d-3d78372ca6f9}">
       Delete
    </A>
    

    更多javascripty:

    <A href="#" 
          onclick="DeleteItem('DeleteItem.aspx?ItemGuid={19a149db-5675-4eee-835d-3d78372ca6f9}')">
       Delete
    </A>
    

    并添加脚本:

    <script type="text/javascript">
       //<![CDATA[
           function DeleteItem(deleteUrl)   
           {   
              //Ask the user if they really want to
              if (!confirm("Are you sure you want to delete INSERT NAME HERE?"))
              {
                 return false;
              }
    
              //Call returns false if the server returned anything other than OK
              if (!DoAjaxHit(deleteUrl)
              {
                 return false;
              }
    
              //Remove the table row from the browser
              var tableRow = document.getElementById("TODO-WHAT ID");
              if (row != null)
              {
                 //TODO: how to delete the tableRow from the DOM tree?
                 //document.Delete(tableRow) ?
              }
    
              //return false to prevent a postback
              return false;
           }
       //]]>
    </script>
    

    可以使用什么组合的ASP代码来创建上述内容?我听说 asp:LinkBut​​ton 有一个 OnClientClick 事件,您可以在其中连接一个javascript函数:

    <asp:LinkButton ID="linkDelete" runat="server"
       Text="Delete"
       OnClientClick="DeleteItem(<%# GetDeleteUrl((ActionItem)Container.DataItem) %>);"/>
    

    问题是呈现的HTML实际上包含:

    <a onclick="DeleteItem(&lt;%# GetDeleteUrl((ActionItem)Container.DataItem)) %>);" ...>
       Delete
    </a>
    

    如果我将客户端点击事件处理程序更改为:

       OnClientClick="DeleteItem('todo - figure this out');"/>
    

    它的工作原理 - 以及“todo - 想出这个”可以起作用。


    预防回发

    实际上发生了javascript调用上面的dummied(我可以看到我的警报),但是还有下一个问题:从javascript函数返回false并不会阻止回发。事实上,我可以看到生成的html代码上的 href 不是“#”,而是

    javascript:__doPostBack('ctl0....
    

    我尝试更改ASPX代码以自己包含OnClick处理程序:

       OnClick="#"
       OnClientClick="DeleteItem('todo - figure this out');"
    

    但是编译器认为英镑是一个pragma,并且发牢骚:

      

    预处理程序指令必须显示为   第一个非空白字符   一行


    表格行标识

    表格行没有ID,它们是由 asp:repeater 生成的。

    javascript函数如何知道是什么触发了click事件? javascript需要能够找到该元素,并将其从树中删除。

    注意:我当然更喜欢淡入淡出+折叠动画。

    通常使用

    获取元素
    var tr = document.getElementById("the table row's id");
    

    但是表行没有容易知道的ID。由于存在多行,因此服务器在构建表时会生成ID。我意识到一些解决方案将不得不涉及改变:

    <TR>
    

    <TR runat="server">
    

    这样每个表行都会有服务器生成的标识,但是如何从javsscript引用生成的名称?

    通常我会认为脚本问题可以通过使用多个参数来解决:

    function DeleteItem(tableRowElement, deleteUrl)
    {
       //Do a web-hit of deleteUrl to delete the item
    
    
       //remove tableRowElement DOM object from the document tree
    }
    

    但问题只是推到别处:你如何填充tableRowElement和deleteUrl来调用javascript函数?


    这是一个简单的问题:将点击从回发转换为客户端。

    所涉问题的数量越来越愚蠢。这似乎表明要么

    • 理念解决方案完全不同
    • 没有解决方案

    参考

    Stackoverflow: How do I fade a row out before postback?

    Stackoverflow: Javascript before asp:ButtonField click

    asp.net: Accessing repeater elements from javascript.

    Stackoverflow: How to access repeater generated elements?

4 个答案:

答案 0 :(得分:4)

jQuery可以为您挖掘标签:

$("[id$=linkDelete]").click(function() {
    DeleteItem(this.href);
});

该代码说“找到ID以'linkDelete'结尾的所有DOM元素,并连接以下click事件处理程序”。

答案 1 :(得分:3)

我建议不要以这种方式通过链接实现删除功能。 Delete links are a security risk.

相反,最好要求在该网址上添加帖子。如果你想做ajax,我强烈建议使用javascript框架,这样你就不必处理不同浏览器如何实现XmlHttpRequests的差异。

例如,在jQuery中你可以这样做:

$.post('Delete.aspx',{itemGuid:'{19a149db-5675-4eee-835d-3d78372ca6f9}'},
    function(data, textStatus) {
        if (textStatus == 'success') {
            $(this).parents('tr:eq(0)').fadeOut();
        }
    });

可以同时执行ajax调用你想要的淡出效果。

然后,您可以从Request.Form [“itemGuid”]访问Delete.aspx中的项目guid,这不会受到链接攻击的影响。

预防回发

服务器正在生成回发连线,因为您正在使用服务器控件。使用普通<a>标签而不使用runat ='server'指令。

表格行标识

我通常通过数据绑定某种类型的ID列并将其放入转发器模板来执行此操作:

<tr id='<%#Eval("ID")%>'>

P.S。我讨厌听起来像一个粉丝,但jQuery将使所有这些事情变得更容易一个数量级。如果可以,你应该考虑它。否则,您将陷入一个受害的世界,试图以一致的方式跨浏览器实现这些功能。

P.P.S。如果只从javascript调用Delete.aspx和类似网址,我建议使用ashx http处理程序。你可以完成所有相同的服务器逻辑,而不需要一个完整页面的不必要的开销。

答案 2 :(得分:0)

我常常看起来像

<asp:LinkButton runat="server" OnClientClick='<%# Eval("ID", "DeleteItem(this, \"{0}\"); return false;") %>' Text="Delete" />

将使html看起来像

<a id="blah_blah_ctl01" onclick='DeleteItem(this, "{19a149db-5675-4eee-835d-3d78372ca6f9}"); return false;'>Delete</a>

我包含“this”引用,以便您可以访问dom并删除链接...或者它的父级或其他内容。从那里开始使用jQuery实际上进行发布和DOM操作非常简单。 “回归虚假”;禁用回发。

答案 3 :(得分:0)

其他回答者发现了与问题的不同方面有关的各种问题。我设法凑齐了一个完整的解决方案。我在这里复制/粘贴了相关的snippits。

第一个重要的变化是使用 asp:LinkBut​​ton ,它允许 OnClientClick 事件,这使您可以直接访问javascript OnClick 事件:

<asp:repeater ID="itemsRepeater"
      OnItemDataBound="itemsRepeater_ItemDataBound"
      runat="Server">
   <itemtemplate>
      <tr>         
         <td>
            <asp:HyperLink ID="linkView" runat="server"
               Text="<%# GetItemText((Item)Container.DataItem) %>"
               NavigateUrl="<%# GetViewItemUrl((Item)Container.DataItem) %>" />
         </td>
         <td>
            <asp:LinkButton ID="linkImpregnate" runat="server"
                   Text="Impregnate"
                   OnClientClick="<%# GetImpregnateUrl((Item)Container.DataItem) %>" />
         </td>
      </tr>
   </itemtemplate>
</asp:repeater>

代码隐藏手动构建包含javascript调用的表示代码(yay用于分离控制器和视图!)。

protected string GetNodeAcknowledgementClientClick(Item item)
{
   if (!(item is HotGirl))
      return ""; //this shouldn't be called for non-acknowledgements, but i won't fail

   HotGirl girl = (HotGirl)item;

   String szOnClientClick =
         "return ImpregnateGirl(this, "+
               Toolkit.QuotedStr(girl.GirlGUID.ToString()) + ", "+
               Toolkit.QuotedStr(GetItemName(item))+");";

   return szOnClientClick;
}

最后在aspx中,我找到了一个随机点来混搭一些javascript:

<script type="text/javascript" src="Javascript/jquery.js"></script>  
<script type="text/javascript">
   //<![CDATA[
   function DeleteItem(sender, girlGuid, girlName)   
   {
      if (!confirm("Are you sure you want to impregnate "+girlName+"?"))
      {
         return false;
      }

      $.post(
         'ImpregnateGirl.aspx?GirlGUID='+nodeGuid,
               function(data, textStatus) {
                  if (textStatus == 'success') 
                  {
                     $(sender).parents('tr:eq(0)').hide();
                  }
                  else
                  {
                     return false;
                  }
               }
      );

      //return false to suppress the postback
      return false;
   }
//]]>
</script>

我会让jQuery做一个帖子,作为一个人建议的安全措施,但jQuery会给出错误,而不是发布。而不是照顾我选择不关心。