IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

ASP.NET Discussion :

[2.0 + Ajax] Ajouter dynamiquement des TextBox à un PlaceHolder qui en contient déjà


Sujet :

ASP.NET

  1. #1
    Membre confirmé
    Avatar de strat0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Novembre 2003
    Messages
    288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Novembre 2003
    Messages : 288
    Points : 598
    Points
    598
    Par défaut [2.0 + Ajax] Ajouter dynamiquement des TextBox à un PlaceHolder qui en contient déjà
    Bonjour,

    Je vous explique le topo : j'ai un TreeView. Lorsque l'on clique sur un de ses noms, un certain nombre d'informations le concernant sont récupérées dans le fichier XML source pour être affichées, notamment ses noeuds enfants. Ceux-ci peuvent être d'un nombre "très" variable, donc je dois les ajouter dans un PlaceHolder dynamiquement.

    Par la suite je souhaite que l'utilisateur puisse cliquer sur un bouton "PLUS" afin de faire apparaitre autant de TextBox supplémentaires qu'il le souhaite, afin d'y saisir des informations et finalement les enregistrer dans le fichier XML source.

    Je ne vous cache pas que tous ces besoins créent un beau pataquès dès qu'il s'agit de créer la logique de PostBack.

    J'ai trouvé cette vidéo de Joe Stagner, qui m'a vaguement aidé, mais évidemment mes besoins sont légèrement différents de ce qu'il y explique.

    Voilà où j'en suis niveau code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <asp:XmlDataSource ID="XmlDataSourceGeo" runat="server" DataFile="~/App_Data/thesaurus-Geographique-Sample.xml"
        XPath="/thesaurus/*" CacheExpirationPolicy="Sliding" CacheDuration="60" />
    <asp:TreeView ID="TreeViewGeo" runat="server" DataSourceID="XmlDataSourceGeo" ExpandDepth="0" ShowLines="true" SkipLinkText="" OnSelectedNodeChanged="TreeViewGeo_SelectedNodeChanged"
        OnTreeNodeDataBound="TreeViewGeo_DataBound">
        <DataBindings>
            <asp:TreeNodeBinding DataMember="retenu" ValueField="id" TextField="terme" />
            <asp:TreeNodeBinding DataMember="EP" TextField="terme" FormatString="Employé pour : {0}" SelectAction="None" />
        </DataBindings>
    </asp:TreeView>
    <table><tr><td>
    <asp:UpdatePanel ID="UpdatePanelEP" runat="server">
        <ContentTemplate>
            <asp:PlaceHolder ID="PlaceHolderEP" runat="server" />
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="BoutonPlusEP" EventName="Click" />
        </Triggers>
    </asp:UpdatePanel>
    </td>
    <td>
    <asp:ImageButton ID="BoutonPlusEP" runat="server" ImageUrl="~/images/plus.gif" OnClick="BoutonPlusEP_Click" />
    </td></tr></table>
    Et surtout côté code behind :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    using System;
    using System.Data;
    using System.Xml;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Collections;
     
    public partial class _Default : System.Web.UI.Page 
    {
        static XmlDocument xmlDoc = new XmlDocument();
        static int nbTextBoxEP = 0;
        private TextBox[] textBoxEP;
     
        protected void Page_PreInit(object sender, EventArgs e)
        {
            Control monControl = GetPostBackControl(this.Page);
     
            if ((monControl != null))
            {
                if ((monControl.ClientID.ToString() == "BoutonPlusEP"))
                {
                    nbTextBoxEP++;
                }
            }
        }
     
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            textBoxEP = new TextBox[nbTextBoxEP];
            for (int i = 0; i < nbTextBoxEP; i++)
            {
                TextBox textBox = new TextBox();
                textBox.ID = "TextBoxEP" + i;
                textBox.CssClass = "TextBoxEP";
                PlaceHolderEP.Controls.Add(textBox);
                textBoxEP[i] = textBox;
            }
        }
     
        protected void Page_Load(object sender, EventArgs e)
        {
            xmlDoc.Load(Server.MapPath("~/App_Data/thesaurus-Geographique-Sample.xml"));
            //TreeViewGeo.Nodes.Clear();
            //foreach (XmlNode noeudRetenu in xmlDoc.DocumentElement.SelectNodes("retenu"))
            //{
            //    AddNode(noeudRetenu, TreeViewGeo.Nodes);
            //}
            //TreeViewGeo.CollapseAll();
        }
     
        //protected void AddNode(XmlNode noeud, TreeNodeCollection collecNoeuds)
        //{
        //    collecNoeuds.Add(new TreeNode(noeud.Attributes["terme"].Value, noeud.Attributes["id"].Value));
        //    TreeNode newNoeud = collecNoeuds[collecNoeuds.Count - 1];
        //    if (noeud.HasChildNodes)
        //    {
        //        foreach (XmlNode noeudEnfant in noeud.SelectNodes("retenu"))
        //            AddNode(noeudEnfant, newNoeud.ChildNodes);
        //    }
        //}
     
        public static Control GetPostBackControl(Page maPage)
        {
            Control monControl = null;
            string nomControl = maPage.Request.Params.Get("__EVENTTARGET");
            if (((nomControl != null) && (nomControl != string.Empty)))
            {
                monControl = maPage.FindControl(nomControl);
            }
            else
            {
                foreach (string control in maPage.Request.Form)
                {
                    Control testControl = maPage.FindControl(control);
                    if (testControl is Button)
                    {
                        monControl = testControl;
                    }
                }
     
            }
            return monControl;
        } 
     
        protected void TreeViewGeo_DataBound(object sender, TreeNodeEventArgs e)
        {
            if (e.Node.Text.StartsWith("Employé pour : "))
                e.Node.Text = "<span style=\"color: #CF4DCF\">" + e.Node.Text + "</span>";
        }
     
        protected void TreeViewGeo_SelectedNodeChanged(object sender, EventArgs e)
        {
            TableInfos.Style.Add("display", "");
            if (TreeViewGeo.SelectedNode.Parent != null)
                LabelParent.Text = TreeViewGeo.SelectedNode.Parent.Text;
            TextBoxRetenu.Text = TreeViewGeo.SelectedNode.Text;
            XmlNodeList noeudsEP = xmlDoc.SelectSingleNode(TreeViewGeo.SelectedNode.DataPath).SelectNodes("EP");
            nbTextBoxEP = noeudsEP.Count;
            for (int i = 0; i < noeudsEP.Count; i++)
            {
                TextBox TextBoxEP = new TextBox();
                TextBoxEP.ID = "TextBoxEP" + i;
                TextBoxEP.CssClass = "TextBoxEP";
                TextBoxEP.Text = noeudsEP[i].Attributes["terme"].Value;
                PlaceHolderEP.Controls.Add(TextBoxEP);
            }
        }
     
        protected void BoutonPlusEP_Click(object sender, EventArgs e)
        {
            //TextBox TextBoxEP = new TextBox();
            //TextBoxEP.ID = "TextBoxEP" + PlaceHolderEP.Controls.Count;
            //TextBoxEP.CssClass = "TextBoxEP";
            //PlaceHolderEP.Controls.Add(TextBoxEP);
            //TextBoxEP.Focus();
        }
     
        protected void BoutonSauv_Click(object sender, EventArgs e)
        {
            foreach (TextBox textBox in textBoxEP)
            {
                Response.Write(textBox.Text);
            }
        }
    }
    Un problème qui se pose est que Joe Stagner montre comment ajouter les TextBox au moment de l'évènement OnInit de la page, mais il semble aussi qu'à ce moment là je ne peux pas déterminer quel est le nœud sélectionné dans le TreeView, et donc récupérer les infos dans le fichier XML (notamment le nombre de nœuds enfants).

    De plus, lorsque l'on clique sur le bouton "PLUS", pour l'instant cela n'ajoute dans le meilleur des cas qu'une seule TextBox, pas plus...

    Je suis désolé je me rends compte que mon code n'est sans doute pas très facile à lire et mon cas assez complexe à résoudre, mais je ne vois pas trop comment faire mieux. Peut-être en vous envoyant le code source s'il y a des volontaires.

    Merci d'avance pour vos suggestions.

  2. #2
    Membre confirmé
    Avatar de strat0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Novembre 2003
    Messages
    288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Novembre 2003
    Messages : 288
    Points : 598
    Points
    598
    Par défaut
    Je touche au but. Et soyons honnête, le code Joe Stagner m'a plus embrouillé qu'autre chose, et au final ça marche aussi bien sans.

    Dernier problème à régler : les valeurs saisies dans les TextBox créées par l'utilisateur disparaissent entre deux PostBack, notamment lorsqu'on ajoute une nouvelle TextBox avec le bouton "PLUS" justement.

    Je commence à mieux comprendre le cycle de vie des pages ASP.Net (notamment grâce à ce diagramme qui était encore assez confus pour moi il y a peu), mais là je sèche. Est-ce parce que je recréé les TextBox au dernier moment dans Page_PreRender?

    Question facultative pour mon édification personnelle : Joe Stagner plaçait le le nombre de TextBox à récréer dans une variable "static", mais du coup la valeur était la même pour tous les utilisateurs de la page et des étrangetés apparaissaient. Du coup j'ai placé cette valeur dans le ViewState (je la récupère dans le PageLoad et je la replace à la fin du PreRender)? mais n'y a-t-il pas plus simple? Comme une variable statique qui garde sa valeur entre les PostBack mais limitée en session (mais sans utiliser Session ni ViewState)?

    Voilà où en est mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    public partial class _Default : System.Web.UI.Page
    {
        static XmlDocument xmlDoc = new XmlDocument();
        private int nbTextBoxEP = 0;
     
        protected void Page_Load(object sender, EventArgs e)
        {
            xmlDoc.Load(Server.MapPath("~/App_Data/thesaurus-Geographique-Sample.xml"));
            if (ViewState["nbTextBoxEP"] != null)
                nbTextBoxEP = (int)ViewState["nbTextBoxEP"];
            //TreeViewGeo.Nodes.Clear();
            //foreach (XmlNode noeudRetenu in xmlDoc.DocumentElement.SelectNodes("retenu"))
            //{
            //    AddNode(noeudRetenu, TreeViewGeo.Nodes);
            //}
            //TreeViewGeo.CollapseAll();
        }
     
        protected void TreeViewGeo_DataBound(object sender, TreeNodeEventArgs e)
        {
            if (e.Node.Text.StartsWith("Employé pour : "))
                e.Node.Text = "<span style=\"color: #CF4DCF\">" + e.Node.Text + "</span>";
        }
     
        protected void TreeViewGeo_SelectedNodeChanged(object sender, EventArgs e)
        {
            BoutonSauv.Enabled = true;
            if (TreeViewGeo.SelectedNode.Parent != null)
                LabelParent.Text = TreeViewGeo.SelectedNode.Parent.Text;
            else
                LabelParent.Text = String.Empty;
            TextBoxRetenu.Text = TreeViewGeo.SelectedNode.Text;
            nbTextBoxEP = xmlDoc.SelectSingleNode(TreeViewGeo.SelectedNode.DataPath).SelectNodes("EP").Count;
        }
     
        protected void BoutonPlusEP_Click(object sender, EventArgs e)
        {
            nbTextBoxEP++;
        }
     
        protected void Page_PreRender(object sender, EventArgs e)
        {
            CreateTextBoxEP();
            ViewState["nbTextBoxEP"] = nbTextBoxEP;
        }
     
        //protected void AddNode(XmlNode noeud, TreeNodeCollection collecNoeuds)
        //{
        //    collecNoeuds.Add(new TreeNode(noeud.Attributes["terme"].Value, noeud.Attributes["id"].Value));
        //    TreeNode newNoeud = collecNoeuds[collecNoeuds.Count - 1];
        //    if (noeud.HasChildNodes)
        //    {
        //        foreach (XmlNode noeudEnfant in noeud.SelectNodes("retenu"))
        //            AddNode(noeudEnfant, newNoeud.ChildNodes);
        //    }
        //}
     
        protected void CreateTextBoxEP()
        {
            if (TreeViewGeo.SelectedNode != null)
            {
                XmlNodeList noeudsEP = xmlDoc.SelectSingleNode(TreeViewGeo.SelectedNode.DataPath).SelectNodes("EP");
                for (int i = 0; i < nbTextBoxEP; i++)
                {
                    TextBox TextBoxEP = new TextBox();
                    TextBoxEP.ID = "TextBoxEP" + i;
                    TextBoxEP.CssClass = "TextBoxEP";
                    if (i < noeudsEP.Count)
                        TextBoxEP.Text = noeudsEP[i].Attributes["terme"].Value;
                    PlaceHolderEP.Controls.Add(TextBoxEP);
                }
            }
        }
     
        protected void BoutonSauv_Click(object sender, EventArgs e)
        {
            foreach (TextBox textBox in PlaceHolderEP.Controls)
            {
                Response.Write(textBox.Text);
            }
        }
    }

  3. #3
    Membre confirmé
    Avatar de strat0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Novembre 2003
    Messages
    288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Novembre 2003
    Messages : 288
    Points : 598
    Points
    598
    Par défaut
    Voilà où j'en suis de mon problème.

    Mes TextBox sont recrées dynamiquement dans le Page_PreRender.

    Or il semblerait qu'à ce stade elles ne puissent plus, même en ayant le même ID qu'au précédent PostBack, récupérée les valeurs que l'utilisateur a saisi.

    A priori ça fonctionnerait si je créais ces TextBox dans le Page_Load, mais j'ai besoin de savoir si l'utilisateur a souhaité ajouter des TextBox en cliquant sur le bouton "PLUS", or l'événement OnClick de ce bouton n'est - si j'ai bien compris - traité qu'après le Page_Load.

    Alors comment devrais-je m'y prendre selon vous? Est-ce qu'il y a un autre moment plus propice que le Page_Load pour recréer mes TextBox tout en m'assurant qu'elles conservent bien les valeurs saisies par l'utilisateur?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Ajout et suppression dynamique des textbox avec JavaScript en ASPx.
    Par zakarinalaw dans le forum Développement Web avec .NET
    Réponses: 1
    Dernier message: 29/04/2014, 14h32
  2. Ajouter dynamiquement des lignes à un tableau HTML
    Par jeannot1974 dans le forum Général JavaScript
    Réponses: 14
    Dernier message: 20/11/2006, 15h39
  3. Ajouter dynamiquement des controles.
    Par hopsoid dans le forum MFC
    Réponses: 16
    Dernier message: 05/09/2006, 18h18
  4. [WebForms]Ajouter dynamiquement des checkbox
    Par ardi dans le forum Général Dotnet
    Réponses: 6
    Dernier message: 07/04/2006, 14h01
  5. ajouter dynamiquement des items dans un popup menu
    Par Malone dans le forum Composants VCL
    Réponses: 7
    Dernier message: 23/08/2005, 16h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo