ASP.NET: Как получить доступ к элементам, созданным повторителем из JavaScript? - PullRequest
7 голосов
/ 24 января 2009

У меня есть ряд строк, которые генерируются с использованием 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 фактически удаляет нужный элемент
  • удалить элемент из дерева DOM клиента

Итак, нужно решить четыре проблемы:

  1. Как подключить JavaScript к клиентскому клику по ссылке Удалить .
  2. Как узнать, на какой элемент нажал пользователь Удалить
  3. Предотвратить постбэк
  4. Удалить строку, по которой щелкнул пользователь

Это мой вопрос.

С этого момента вы найдете мои бессвязные попытки решить ее. Не принимайте что-либо ниже как относящееся к любому возможному принятому решению. То, что я разместил код ниже, не означает, что он полезен. И это не значит, что я нахожусь в пределах досягаемости лучшего решения. И потому что я не могу заставить что-то под работой - это, должно быть, пошло не по тому пути.


Мои попытки

Подключение 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: LinkButton имеет событие 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 (я вижу мое предупреждение), но есть следующая проблема: возвращение false из функции javascript не предотвращает обратную передачу. Фактически, я вижу, что href в сгенерированном html-коде - это не "#", а

javascript:__doPostBack('ctl0....

Я попытался изменить код ASPX для включения обработчика OnClick:

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

Но компилятор считает, что сторона фунта - это прагма, и скулит:

Директивы препроцессора должны выглядеть как первый непробельный символ на линия


Идентификация строки таблицы

Строки таблицы не имеют идентификатора, они генерируются asp: repeater .

Как функция javascript может узнать, что вызвало событие click? Javascript должен быть в состоянии найти элемент и удалить его из дерева.

Примечание: Я бы, конечно, предпочел анимацию исчезновения + коллапса.

Обычно вы получаете элемент, используя

var tr = document.getElementById("the table row's 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: как затушить строку перед обратной передачей?

Переполнение стека: Javascript перед asp: нажатие кнопки на поле

asp.net: Доступ к элементам повторителя из javascript.

Stackoverflow: как получить доступ к элементам, созданным повторителем?

Ответы [ 4 ]

4 голосов
/ 24 января 2009

jQuery может найти для вас теги:

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

Этот код говорит: «найдите все элементы DOM, чей идентификатор заканчивается на« linkDelete », и подключите следующий обработчик события нажатия».

3 голосов
/ 24 января 2009

Я бы не рекомендовал реализовывать функцию Delete через ссылки таким способом. Удаление ссылок представляет угрозу безопасности.

Скорее, вместо этого лучше требовать пост на этот URL. Если вы хотите использовать 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 и требуемый эффект затухания.

После этого вы можете получить доступ к guid элемента в Delete.aspx из Request.Form ["itemGuid"], и это не будет уязвимо для атак по ссылкам.

Предотвращение обратных передач

Сервер генерирует обратную связь, потому что вы используете серверный элемент управления. Используйте простой тег <a> без директивы runat = 'server'.

Идентификатор строки таблицы

Обычно я делаю это, привязывая к некоторому виду столбец ID и помещая это в шаблон повторителя:

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

P.S. Ненавижу звучать как фанат, но jQuery сделает все это на порядок проще. Вы должны действительно рассмотреть это, если можете. В противном случае вы окажетесь в затруднительном положении, пытаясь последовательно реализовать эти функции в разных браузерах.

P.P.S. Если Delete.aspx и аналогичные URL будут вызываться только из javascript, я бы рекомендовал вместо этого использовать http-обработчики ashx. Вы можете выполнять всю ту же логику сервера без лишних затрат на полноценную страницу.

0 голосов
/ 10 февраля 2009

Другие авторы нашли различные сведения, связанные с различными аспектами вопроса. Мне удалось собрать полное решение. Я скопировал / вставил соответствующие фрагменты здесь.

Первым важным изменением является использование asp: LinkButton , которое разрешает как 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>

Кодовая часть вручную создает код представления (yay для разделения контроллера и представления!), Который содержит вызов javascript.

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 выдает ошибку, а не публикацию. Вместо того, чтобы заботиться, я решил не заботиться.

0 голосов
/ 24 января 2009

моя обычно выглядит как

<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. «Возвращение ложного»; отключает обратную передачу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...