Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET: How to access repeater generated elements from javascript?

Tags:

ajax

asp.net

i have a series of rows that are generated using an 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>

The repeater creates an HTML table, with each row containing a link to an item and (what is essentially) a "Delete" link. The above simplified example code generates HTML similar to:

<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>

Now that all works, but i want to convert the "Delete" to client side. i want to be able click the link and it will, on the client javascript:

  • prompt an alert "Are you sure..."
  • have javascript issue server-hit to actually delete the item they want
  • remove the item from the client DOM tree

So there are four problems to be solved:

  1. How to hook up javascript to the client-side click of the Delete link.
  2. How to know what item the user clicked Delete
  3. Prevent a post-back
  4. Delete the row that the user clicked

That is my question.

From here on you will find my rambling attempts to solve it. Don't take anything below as relating in any way to any possible accepted solution. Just because i posted code below, doesn't mean any of it is useful. And it doesn't mean i'm anywhere within spitting distance of the best solution. And because i can't make anything below work - it must have gone down the wrong road.


My Attempts

Wiring Up Javascript

The first task is to convert the delete link HTML from something such as:

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

into something more javascripty:

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

and the add the script:

<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>

What combination of ASP code can be used to create the above? i hear that asp:LinkButton has an OnClientClick event, where you can wire up a javascript function:

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

Problem is that the rendered HTML is literally containing:

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

If i change the client click event handler to:

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

it works - as well as "todo - figure this out" can work.


Preventing Postbacks

The dummied down above javascript call actually happens (i can see my alert), but there's the next problem: Returning false from the javascript function doesn't prevent a postback. In fact, i can see that the href on the generated html code isn't "#", but rather

javascript:__doPostBack('ctl0....

i tried changing the ASPX code to include the OnClick handler myself:

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

But the compiler thinks the pound side is a pragma, and whines:

Preprocessor directives must appear as the first non-whitespace character on a line


Table Row Identity

The table rows don't have an ID, they're generated by the asp:repeater.

How can the javascript function know what triggered the click event? The javascript needs to be able to find the element, and remove it from the tree.

Note: i would of course prefer fade+collapse animation.

Normally you get an element by using

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

But the table rows don't have an easily knowable ID. Since there are multiple rows, the server generates the ID as it builds the table. i realize some solution is going to have to involve changing:

<TR>

into

<TR runat="server">

so that there will be server generated identity for each table row, but how do i reference the generated name from javsscript?

Normally i would have thought that the scripting problem would be solved by using multiple paramters:

function DeleteItem(tableRowElement, deleteUrl)
{
   //Do a web-hit of deleteUrl to delete the item


   //remove tableRowElement DOM object from the document tree
}

But the problem is just pushed elsewhere: How do you populate tableRowElement and deleteUrl for the call to the javascript function?


Such a simple problem: convert a click from a postback to client-side.

The volume of problems involved is getting quite idiotic. Which seems to indicate that either

  • the idea solution is something completely different
  • there is no solution

References

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?

like image 721
Ian Boyd Avatar asked Jan 23 '09 21:01

Ian Boyd


2 Answers

jQuery can dig out the tags for you:

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

That code says "find all the DOM elements whose ID ends with 'linkDelete' and wire up the following click event handler".

like image 90
OdeToCode Avatar answered Sep 18 '22 02:09

OdeToCode


I would recommend against implementing the Delete function through links in this way. Delete links are a security risk.

Rather, it's better to require a post to that url instead. If you want to be doing ajax, I would strongly recommend using a javascript framework so you don't have to deal with the differences in how different browsers implement XmlHttpRequests.

For instance, in jQuery you could do it like this:

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

which would do both the ajax call and the fadeout effect you want.

You could then access the item guid in Delete.aspx from Request.Form["itemGuid"], and this wouldn't be vulnerable to link attacks.

Preventing Postbacks

The server is generating a postback wireup because you're using a server control. Use a plain <a> tag without a runat='server' directive.

Table Row Identity

I usually do this by databinding an ID column of some kind and putting this in the repeater template:

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

P.S. I hate to sound like a fanboy, but jQuery will make all of these things an order of magnitude easier. You should really consider it if you can. Otherwise, you're going to be in a world of hurt trying to implement these features in a consistent way across browsers.

P.P.S. If the Delete.aspx and similar urls are only going to be called from javascript, I would recommend using ashx http handlers instead. You can do all of the same server logic without the needless overhead of a full-blown page.

like image 22
Adam Lassek Avatar answered Sep 21 '22 02:09

Adam Lassek