7 votes

ASP.NET : Comment accéder aux éléments générés par le répéteur à partir de javascript ?

J'ai une série de lignes qui sont générées à l'aide d'un système de gestion des données. asp:répéteur :

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

Le répéteur crée un tableau HTML, dont chaque ligne contient un lien vers un élément et (ce qui est essentiellement) un lien "Supprimer". L'exemple de code simplifié ci-dessus génère un code HTML similaire à celui-ci :

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

Maintenant, tout cela fonctionne, mais je veux convertir la "suppression" en côté client. Je veux être en mesure de cliquer sur le lien et il sera, sur le client javascript :

  • déclencher une alerte "Êtes-vous sûr..."
  • faire en sorte que le javascript soit utilisé par le serveur pour supprimer l'élément qu'ils souhaitent.
  • supprimer l'élément de l'arbre DOM du client

Il y a donc quatre problèmes à résoudre :

  1. Comment relier le javascript au clic côté client de l'interface utilisateur ? Supprimer lien.
  2. Comment savoir sur quel élément l'utilisateur a cliqué Supprimer
  3. Empêcher un retour en arrière
  4. Supprimer la ligne sur laquelle l'utilisateur a cliqué

C'est ma question.

À partir d'ici, vous trouverez mes tentatives décousues pour le résoudre. Ne considérez pas que ce qui suit est lié de quelque manière que ce soit à une solution acceptée. Ce n'est pas parce que j'ai posté du code ci-dessous qu'il est utile. Et ça ne veut pas dire que je suis à deux doigts de trouver la meilleure solution. Et parce que je ne peux pas faire fonctionner quoi que ce soit ci-dessous - ça doit être une erreur.


Mes tentatives

Câblage de Javascript

La première tâche consiste à convertir le lien de suppression HTML de quelque chose comme :

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

en quelque chose de plus "javascripty" :

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

et ajouter le 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>

Quelle combinaison de code ASP peut être utilisée pour créer ce qui précède ? J'ai entendu dire que asp:LinkButton a un OnClientClick dans lequel vous pouvez insérer une fonction javascript :

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

Le problème, c'est que le HTML rendu est littéralement contenant :

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

Si je change le gestionnaire d'événement de clic du client en :

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

ça marche - aussi bien que "todo - figure this out" peut marcher.


Prévention des retours en arrière

L'appel javascript simplifié ci-dessus fonctionne réellement (je peux voir mon alerte), mais il y a un autre problème : Retourner false de la fonction javascript n'empêche pas un postback. En fait, je peux voir que la fonction href sur le code html généré n'est pas "#", mais plutôt

javascript:__doPostBack('ctl0....

J'ai essayé de modifier le code ASPX pour inclure moi-même le gestionnaire OnClick :

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

Mais le compilateur pense que le côté pound est un pragma, et se plaint :

Les directives du préprocesseur doivent apparaître sous la forme le premier caractère non espace sur une ligne


Identité de la rangée de la table

Les lignes de la table n'ont pas d'identifiant, elles sont générées par la fonction asp:répéteur .

Comment la fonction javascript peut-elle savoir ce qui a déclenché l'événement de clic ? Le javascript doit être capable de trouver l'élément et de le supprimer de l'arbre.

Nota: Je préférerais bien sûr une animation de type fondu + effondrement.

Normalement, vous obtenez un élément en utilisant

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

Mais les lignes de la table n'ont pas d'ID facile à connaître. Comme il y a plusieurs lignes, le serveur génère l'ID lorsqu'il construit la table. Je me rends compte qu'une solution devra être modifiée :

<TR>

en

<TR runat="server">

afin qu'il y ait une identité générée par le serveur pour chaque ligne de la table, mais comment puis-je référencer le nom généré à partir du javsscript ?

Normalement, j'aurais pensé que le problème des scripts serait résolu par l'utilisation de paramètres multiples :

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

   //remove tableRowElement DOM object from the document tree
}

Mais le problème est simplement repoussé ailleurs : Comment remplir tableRowElement et deleteUrl pour l'appel à la fonction javascript ?


Un problème si simple : convertir un clic d'un postback en client-side.

Le volume des problèmes en jeu devient tout à fait stupide. Ce qui semble indiquer que soit

  • l'idée solution est quelque chose de complètement différent
  • il n'y a pas de solution

Références

Stackoverflow : Comment faire disparaître une ligne avant le postback ?

Stackoverflow : Javascript avant le clic sur asp:ButtonField

asp.net : Accès aux éléments répétiteurs à partir de javascript.

Stackoverflow : Comment accéder aux éléments générés par le répéteur ?

4voto

OdeToCode Points 2421

jQuery peut déterrer les étiquettes pour vous :

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

Ce code dit "trouver tous les éléments DOM dont l'ID se termine par 'linkDelete' et mettre en place le gestionnaire d'événement de clic suivant".

3voto

Adam Lassek Points 18918

Je vous déconseille de mettre en œuvre la fonction de suppression par le biais de liens de cette manière. Les liens supprimés constituent un risque pour la sécurité.

Il est plutôt préférable de demander un post à cette url. Si vous voulez faire de l'ajax, je vous recommande fortement d'utiliser un framework javascript pour ne pas avoir à gérer les différences dans la façon dont les différents navigateurs implémentent les XmlHttpRequests.

Par exemple, en jQuery, vous pouvez procéder comme suit :

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

qui ferait à la fois l'appel ajax et l'effet de fondu enchaîné que vous souhaitez.

Vous pourriez alors accéder au guide de l'élément dans Delete.aspx à partir de Request.Form["itemGuid"], et cela ne serait pas vulnérable aux attaques par lien.

Prévention des retours en arrière

Le serveur génère un postback wireup parce que vous utilisez un contrôle de serveur. Utilisez un simple <a> sans directive runat='server'.

Identité de la rangée de la table

Je le fais généralement en liant les données d'une colonne d'identification quelconque et en la plaçant dans le modèle de répétiteur :

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

P.S. Je déteste passer pour un fan, mais jQuery rendra toutes ces choses beaucoup plus faciles. Vous devriez vraiment l'envisager si vous le pouvez. Sinon, vous aurez beaucoup de mal à mettre en œuvre ces fonctionnalités de manière cohérente dans tous les navigateurs.

P.P.S. Si l'url Delete.aspx et les urls similaires ne sont appelées qu'à partir de javascript, je recommande d'utiliser plutôt des gestionnaires de http ashx. Vous pouvez faire la même logique de serveur sans la surcharge inutile d'une page complète.

0voto

Al W Points 4795

Le mien ressemble généralement à

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

qui produira du html qui ressemble à

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

J'inclus la référence "this" pour que vous puissiez avoir accès au DOM et supprimer le lien... ou son parent ou autre. À partir de là, il est assez simple d'utiliser jQuery pour effectuer l'affichage et la manipulation du DOM. Le "return false ;" désactive le postback.

0voto

Ian Boyd Points 50743

Les autres personnes qui ont répondu ont trouvé divers éléments liés à différents aspects de la question. J'ai réussi à rassembler une solution complète. J'ai copié/collé les extraits pertinents ici.

Le premier changement important est l'utilisation d'un asp:LinkButton qui permet comme OnClientClick qui vous donne un accès direct au javascript. OnClick événement :

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

Le code-behind construit manuellement le code de présentation (hourra pour la séparation du contrôleur et de la vue !) qui contient un appel 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;
}

Et enfin, dans l'aspx, je trouve un endroit au hasard pour insérer du 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>

J'aurais fait en sorte que le jQuery fasse un post, par mesure de sécurité comme le suggère le gars, mais le jQuery donne une erreur, plutôt que de poster. Plutôt que de m'en soucier, j'ai choisi de ne pas m'en soucier.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X