Udostępnij za pośrednictwem


Wie referenziere ich in JavaScript ein Control dessen Namen durch INamingContainer geändert wurde?

Was ist das Problem?

Vielleicht haben Sie schon bemerkt, dass clientseitige IDs von Controls gelegentlich von den ursprünglich vergebenen IDs abweichen. Dieses Phänomen tritt immer dann auf, wenn Controls in Container eingefügt werden, die das Interface INamingContainer implementieren. Anbei ein kleines Beispiel:

<

asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server"> <asp:TextBox ID="TextBox1" runat="server" /> <br /> <asp:Button ID="Button1" runat="server" Text="Button" /></asp:Content>

In diesem Beispiel wurden zwei Controls in einen ContentPlaceHolder eingefügt woraus ASP.NET den folgenden Markup Code erzeugt:

<div>    <input name="ctl00$ContentPlaceHolder1$TextBox1" type="text" id="ctl00_ContentPlaceHolder1_TextBox1" />    <br />    <input type="submit" name="ctl00$ContentPlaceHolder1$Button1" value="Button" id="ctl00_ContentPlaceHolder1_Button1" /></div>

Problematisch wird es nun, wenn Sie versuchen in JavaScript über die ID des Controls auf das Control zuzugreifen. Da die ID des Controls von ASP.NET geändert wurde findet getElementById in dem folgenden Beispiel kein Control und der Code resultiert in einem Scriptfehler (Fehler 21, Objekt erforderlich).

<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">    <script type="text/javascript">        function SayHello() {            alert("Hallo " + document.getElementById("TextBox1").value);        }     </script>

    <asp:TextBox ID="TextBox1" runat="server" />     <br />     <asp:Button ID="Button1" runat="server" Text="Button" OnClientClick="SayHello();" />

</asp:Content>

Warum verhält sich ASP.NET so?

In dem Beispiel ändert ASP.NET den Namen der Controls um eindeutige IDs auf dem Client zu garantieren. Befände sich beispielsweise auf der Seite ein weiterer ContentPlaceHolder mit einer TextBox mit gleicher ID käme es zu einem Namenskonflikt. Verantwortlich für diese Änderung ist das Interface INamingContainer. Wenn ein Control INamingContainer implementiert (in diesem Fall ContentPlaceHolder1) erzeugt ASP.NET UniqueIDs für jedes ChildControl (in diesem Fall TextBox1 und Button1) indem die UniqueID des NamingContainers und die UniqueID des ChildControls mit einem Doppelpunkt verknüpft werden. Um clientseitig auf ein Control zugreifen zu können gibt es die ClientID die ebenso wie die UniqueID eindeutig für eine Webseite ist. Die ClientID ist die "scriptfreundliche" Version der UniqueID und verwendet im Gegensatz zu der UniqueID einen Unterstrich als Trennzeichen.

Was ist die Lösung?

Neben der Möglichkeit die voraussichtliche ClientID im Vorfeld in den JavaScript Code einzufügen (nein, das wollen Sie NICHT!!!) können Sie die ClientID über DataBinding Inline Code in Ihren Code überführen:

<script type="text/javascript">

    function SayHello() {         var con = document.getElementById("<%= TextBox1.ClientID %>");         alert("Hallo " + con.value);     }

</script>

Alternativ haben Sie übrigens auch die Möglichkeit die ClientID über ClientScript.RegisterClientScriptBlock auf der Seite verfügbar zu machen:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    Dim js As String = "function GetTextBox1() { return document.getElementById('" & TextBox1.ClientID & "'); }"     ClientScript.RegisterClientScriptBlock(Me.GetType, "TextBox1_ClientID", js, True)

End Sub

Happy Coding!

Daniel

20071018 - DataBinding Inline Code; Danke Hannes!

Comments

  • Anonymous
    October 17, 2007
    PingBack from http://msdnrss.thecoderblogs.com/2007/10/17/wie-referenziere-ich-in-javascript-ein-control-dessen-namen-durch-inamingcontainer-geandert-wurde/

  • Anonymous
    October 17, 2007
    Hi Daniel, da hatte peter auch mal was zu geschrieben: http://www.aspnetzone.de/blogs/peterbucher/archive/2007/04/09/artikel-identifizierung-von-controls-control-id-clientid-uniqueid.aspx

  • Anonymous
    March 11, 2008
    Die ganze Sache wird etwas komplizierter, wenn man Labels oder Textboxen in einem UserControl dynamisch erzeugt und dieses wiederum dynamisch zur Laufzeit läd. Wie Peter Bucher bereits geschrieben hat, ist die ClientID abhängig von den umgebenden Containern und daher zum Zeitpunkt der Erstellung noch nicht hinreichend bekannt. Für alle die wie ich mit diesem Problem zu kämpfen haben: die Lösung heißt OnPreRender! Wenn man die ClientID hier abfragt erhält man die tatsächliche ClientID. Happy Coding! Viele Grüße Mascha

  • Anonymous
    April 06, 2008
    The comment has been removed

  • Anonymous
    May 08, 2008
    Wenn man sicher ist, dass das Control wirklich eine eindeutige ID hat, kann man es trotzdem mit Javascript finden. Das geht dann auch wenn der JavaScript code in *.js Dateien ausgelagert ist. Siehe z.B. mein Post: http://peter.hahndorf.eu/blog/2008/05/09/getElementByIdProblemsInAspnet.aspx

  • Anonymous
    September 01, 2008
    Wie den meisten schon bekannt sein wird, erzeugt ASP.NET ClientIDs die auf dem Client genutzt werden

  • Anonymous
    September 03, 2008
    Hi@all, Danke für die Tipps. Dieses Verhalten ist Clientseitig ziemlich nervend und auch unerwünscht. ASP.NET soll schauen, dass es Serverseitig "flutscht". Eindeutige IDs für JS habe ich auch ohne/vor ASP.NET hinbekommen! Nochamls vielen Dank. Grüße Holger Matthias Rößler