Search code examples
asp.nettextboxupdatepanelrepeater

Repeater Autopostback Textbox Focus Position issue


I have a repeater control that contains a Textbox within an UpdatePanel, as well as other controls. The repeater fetches data from an SQL database and when the user makes changes to this specific textbox, the OnTextChange event is fired when the user "tabs out" of the text box. This event triggers a Stored Procedure code to update the databse with the new values in the textbox. The functionality I'd like to implement is when the user tabs out of the text box, the next text box in the repeater row should be focused on for continuous editing (similar to an excel spreadsheet) after the AutoPostBack from the OnTextChange event is fired. Would anyone have an example on how to do this using the code i have provided below? Thank you in advance!

Form Markup:

     <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
                        <asp:Repeater ID="GradeEditor" runat="server">
        <ItemTemplate>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="True">
                <ContentTemplate>
                <asp:Panel ID="Panel1" runat="server" Width="100%" Height="100%">
                    <table style="width:100%;">
                        <tr>
                            <td>
                                <asp:Label ID="LateLabel" runat="server" CssClass="label label-success" Visible="False"></asp:Label>
                            </td>
                            <td>&nbsp;</td>
                        </tr>
                        <tr>
                            <td colspan="2">
                                <asp:TextBox ID="TextBox1" runat="server" AutoPostBack="True" BackColor="Transparent" BorderColor="Transparent" OnTextChanged="Grade_TextChanged" style="text-align: center" Text='<%# Bind("Grade_Code") %>' Width="100%"></asp:TextBox>
                            </td>
                        </tr>
                    </table>
                <asp:Label ID="Label4" runat="server" Text='<%# Bind("ID") %>' Visible="False"></asp:Label>
                <asp:HiddenField ID="HiddenField1" runat="server" Value='<%# Bind("ID") %>' />
                <asp:HiddenField ID="HiddenField2" runat="server" Value='<%# Bind("Class_ID") %>' />
                <asp:HiddenField ID="HiddenField3" runat="server" Value='<%# Bind("Assignment_ID") %>' />
                <asp:HiddenField ID="HiddenField4" runat="server" Value='<%# Bind("Student_ID") %>' />
                <asp:HiddenField ID="HiddenField5" runat="server" Value='<%# Bind("Exempt") %>' />
                </asp:Panel>    
                 </ContentTemplate>
            </asp:UpdatePanel>
        </ItemTemplate>
    </asp:Repeater>

Code Behind for Update:

        Protected Sub Grade_TextChanged(sender As Object, e As EventArgs)
    'Find the reference of the Repeater Item.
    Dim ScoreText As TextBox = CType(sender, TextBox)
    Dim item As RepeaterItem = CType(ScoreText.NamingContainer, RepeaterItem)
    Dim ScoreID As Integer = Integer.Parse(TryCast(item.FindControl("HiddenField1"), HiddenField).Value)
    Dim ClassID As Integer = TryCast(item.FindControl("HiddenField2"), HiddenField).Value.Trim()
    Dim AssignmentID As String = TryCast(item.FindControl("HiddenField3"), HiddenField).Value.Trim()
    Dim StudentID As String = TryCast(item.FindControl("HiddenField4"), HiddenField).Value.Trim()
    Dim Grade As String = TryCast(item.FindControl("TextBox1"), TextBox).Text

    Dim constr As String = ConfigurationManager.ConnectionStrings("AthenaConnectionString").ConnectionString
    Using con As New SqlConnection(constr)
        Using cmd As New SqlCommand("Scores_CRUD")
            cmd.CommandType = CommandType.StoredProcedure
            cmd.Parameters.AddWithValue("@Action", "UPDATE")
            cmd.Parameters.AddWithValue("@Score", Grade)
            cmd.Parameters.AddWithValue("@ScoreID", ScoreID)
            cmd.Connection = con
            con.Open()
            cmd.ExecuteNonQuery()
            con.Close()
        End Using
    End Using
    Me.BindRepeater()
End Sub

Solution

  • You have an issue in your markup with UpdatePanel. The UpdatePanel should have the Repeater control within its ContentTemplate as in markup below.

    Change your code to as given below.

    Correct Markup

    <asp:UpdatePanel ID="UpdatePanel1" runat="server" ChildrenAsTriggers="True">
       <ContentTemplate>
          <asp:Repeater ID="GradeEditor" runat="server">
             <ItemTemplate>
                <asp:Panel ID="Panel1" runat="server" Width="100%" Height="100%">
                   <table style="width:100%;">
                      <tr>
                         <td>
                            <asp:Label ID="LateLabel" runat="server" CssClass="label label-success" Visible="False"></asp:Label>
                         </td>
                         <td>&nbsp;</td>
                      </tr>
                      <tr>
                         <td colspan="2">
                            <asp:TextBox ID="TextBox1" runat="server" AutoPostBack="True" BackColor="Transparent" BorderColor="Transparent" OnTextChanged="Grade_TextChanged" style="text-align: center" Text='<%# Bind("Grade_Code") %>' Width="100%"></asp:TextBox>
                         </td>
                      </tr>
                   </table>
                   <asp:Label ID="Label4" runat="server" Text='<%# Bind("ID") %>' Visible="False"></asp:Label>
                   <asp:HiddenField ID="HiddenField1" runat="server" Value='<%# Bind("ID") %>' />
                   <asp:HiddenField ID="HiddenField2" runat="server" Value='<%# Bind("Class_ID") %>' />
                   <asp:HiddenField ID="HiddenField3" runat="server" Value='<%# Bind("Assignment_ID") %>' />
                   <asp:HiddenField ID="HiddenField4" runat="server" Value='<%# Bind("Student_ID") %>' />
                   <asp:HiddenField ID="HiddenField5" runat="server" Value='<%# Bind("Exempt") %>' />
                </asp:Panel>
             </ItemTemplate>
          </asp:Repeater>
       </ContentTemplate>
    </asp:UpdatePanel>
    

    Then, you need to emit JavaScript for focusing the next textbox from the text changed event of textbox in Repeater. This can be done using C# code as below.

    Text changed event C# code for focusing the next box

    protected void Grade_TextChanged(object sender, EventArgs e) {
    
       //PUT your original code for calling stored procedure here
    
       TextBox textBox = sender as TextBox;
    
       BindRepeater();
    
       RepeaterItem currentRepeaterItem = (RepeaterItem)(textBox.NamingContainer);
       int currentRepeaterItemIndex = currentRepeaterItem.ItemIndex;
    
       RepeaterItem nextRepeaterItem = null;
    
       //get the next item row of Repeater
       if ((rptCustomers.Items.Count - 1) >= (currentRepeaterItemIndex + 1)) {
        nextRepeaterItem = GradeEditor.Items[currentRepeaterItemIndex + 1];
       }
    
       if (nextRepeaterItem != null) {
        //get the textbox in next row of Repeater
        TextBox nextTextBox = nextRepeaterItem.FindControl("TextBox1") as TextBox;
    
        //emit JavasSript to focus the next textbox
        ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "focusnext", String.Format(" var nextTextBox = document.getElementById('{0}'); nextTextBox.focus(); nextTextBox.select();", nextTextBox.ClientID), true);
       }
    }