3

I have my setup below. When rendering the page it throws this error: The name 'UserName' does not exist in the current context. I don't understand why because my control is right above the call. I have this same setup in a separate control and it works just fine. Can anyone explain this?

<asp:TextBox ID="UserName" runat="server" Width="136px"></asp:TextBox>

<asp:CustomValidator ID="cvUserNameOrEmailRequired" ValidationGroup="LoginForm" 
    runat="server" CssClass="input-error" ErrorMessage="Username is required"
    ControlToValidate="UserName" Display="Dynamic" 
    ClientValidationFunction="UsernameValidateTextBox" ValidateEmptyText="True">
    </asp:CustomValidator>

<script type="text/javascript">
    function UsernameValidateTextBox(source, arguments) {
        if (arguments.Value % 2 == 0) {
            arguments.IsValid = false;
        } else {
            arguments.IsValid = true;
        }
    }
    **//ERROR IS THROWN HERE**
    $("#<%=UserName.ClientID %>").focus(function () {
        $("#<%=cvUserNameOrEmailRequired.ClientID %>").css({ visibility: "hidden" });
    });
</script>

UPDATE

If I remove this call:$("#<%=UserName.ClientID %>").focus(function () { I then get the same error for <%=cvUserNameOrEmailRequired.ClientID %>

The code above is inside a <asp:Login> tag placing it outside removes the error.

UPDATE

I moved the jQuery code outside of the <asp:Login> and the error went away. I used:

$('#<%=LoginForm.FindControl("UserName").ClientID%>').focus(function () {
    $('#<%=LoginForm.FindControl("cvUserNameOrEmailRequired").ClientID%>')
        .css({ visibility: "hidden" });
});

And no problems. But why doesn't it work within the <asp:Login> tag?

brenjt
  • 15,997
  • 13
  • 77
  • 118
  • I occasionally have white space issues when doing inline insertions like that. I find ASP.NET intolerant to incorrect whitespacing, and to be honest I don't know the official/correct format. Try adding a leading space to <%=Username, or, alternatively, removing the trailing whitespace. – Matt Sep 07 '11 at 15:32
  • @Matt, thanks for the suggestion but it didn't seem to work.... – brenjt Sep 07 '11 at 15:52
  • Are you using .net 4.0? If so, you can use ClientIDMode="Static" on the UserName textbox, and not have to worry about .net changing the id. It will just be 'Username' – ScottE Sep 07 '11 at 16:01
  • That didn't seem to do it either. – brenjt Sep 07 '11 at 16:12
  • I copied your code into my ASP application and there's no squiggly lines. I even checked it online and the textbox shows up just fine. I know it sounds weird, but try copying the code you pasted on this page then copy it over the code you have in your ASP application. It's worked for me before. – Jamie Sep 07 '11 at 19:51
  • Oh I see what you mean. From what I understand you never put the – Jamie Sep 08 '11 at 17:52
  • @jlg, well I sometimes do but mostly at the bottom of the page. But in the case of the example above I have all the code inside an ASP.NET module and so to target the correct control I have to do the script inline on the same page. – brenjt Sep 08 '11 at 18:01
  • Oh I see. It doesn't break anything having the javascript outside then? – Jamie Sep 08 '11 at 18:05
  • @Nope, checkout this answer http://stackoverflow.com/questions/6625773/where-should-i-put-the-css-and-javascript-code-in-an-html-webpage/6625812#6625812 – brenjt Sep 08 '11 at 18:08

1 Answers1

7

The Login control, among others like Repeaters and GridViews, use templates. This takes the controls in those template tags, like the Login's <LayoutTemplate>, out of the Page.Controls list, and puts them in the Login tag's Controls list. So you need a reference to the control within the Login control's list.

This code uses the FindControl() method which iterates through all the direct children of the control looking for an ID by name. The full code below explicitly casts it to the target type, but you could cast to the more generic Control if it would be easier since you're only getting the ClientID property:

((Control)Login1.FindControl("UserName")).ClientID

Also, the Login control is a little special in that it expects certain controls with specific IDs, so it won't render the literal, client-side JavaScript code in the Login LayoutTemplate. So move the literal <script> tag outside of the template. This doesn't solve the reference problem of course, so you still must get a reference to the child control with FindControl().

<asp:Login ID="Login1" runat="server">
    <LayoutTemplate>
        <asp:TextBox ID="Password" runat="server" Width="136px"></asp:TextBox>
        <asp:TextBox ID="UserName" runat="server" Width="136px"></asp:TextBox>
        <asp:CustomValidator ID="cvUserNameOrEmailRequired" ValidationGroup="LoginForm" runat="server"
            CssClass="input-error" ErrorMessage="Username is required" ControlToValidate="UserName"
            Display="Dynamic" ClientValidationFunction="UsernameValidateTextBox" ValidateEmptyText="True">
        </asp:CustomValidator>
    </LayoutTemplate>
</asp:Login>
<script type="text/javascript">
    function UsernameValidateTextBox(source, arguments) {
        if (arguments.Value % 2 == 0) {
            arguments.IsValid = false;
        } else {
            arguments.IsValid = true;
        }
    }
    $("#<%= ((TextBox)Login1.FindControl("UserName")).ClientID %>").focus(function () {
        $("#<%=((CustomValidator)Login1.FindControl("cvUserNameOrEmailRequired")).ClientID %>").css({ visibility: "hidden" });
    });
</script>
Jon Adams
  • 24,464
  • 18
  • 82
  • 120