1

I've got a repeater control containing a textbox and a label. I want to set the label value based on the value the user sets in the textbox, on the client-side to avoid a round-trip to the server.

I wrote a JavaScript function which is called by the textbox OnChange event. Now I just need to access the textbox and label in that function. I understand I should be accessing the controls via <%# Container.FindControl(...).ClientID %> but I cannot get it to work in the OnChange event. I also tried <%# Container.ItemIndex %>, in case there was a problem with the nested quotes, but that didn't work either.

I'm a novice with ASP.NET so I assume I'm missing something obvious.

Here's what I've got so far (currently attempting to use <%# Container.ItemIndex %>):

<asp:Content ID="Content3" ContentPlaceHolderID="regionBody" runat="server">
    <table class="DataGrid">
        <tr class="HeaderStyle">
            <td>Item</td>
            <td>Weight (kg)</td>
            <td>Total Volume (m3):</td>
        </tr>
        <asp:Repeater ID="rptItems" runat="server" 
            OnItemDataBound="rptItems_ItemDataBound" >
            <ItemTemplate>
                <tr class='<%# Container.ItemIndex % 2 == 0 
                            ? "ItemStyle" 
                            : "AlternatingItemStyle"  %>' 
                    style="text-align: center">
                    <td>
                        <asp:Label ID="lblItemNum" runat="server" />
                    </td>
                    <td>
                        <asp:TextBox ID="txtWeight" Height="20px" Width="40px" 
                            runat="server" Visible="true" 
                            OnChange="ValidateItemWeightAndSetVolume(0);" />
                    </td>
                    <td>
                        <asp:Label ID="lblVolume" runat="server" 
                            Visible="true" CssClass="numericLeft" />
                    </td>
                </tr>
            </ItemTemplate>
        </asp:Repeater>
    </table>
</asp:Content>

And here's the JavaScript function:

function ValidateItemWeightAndSetVolume(itemIndex) { 
    var weightId = "regionBody_rptItems_txtWeight_" + itemIndex;
    var volumeId = "regionBody_rptItems_lblVolume_" + itemIndex;
    var txtWeight = document.getElementById(weightId);
    var lblVolume = document.getElementById(volumeId);

    var volume = 0;
    var validated = ValidateItemWeight(txtWeight);
    if (validated) {
        var weight = parseFloat(txtWeight.value);
        volume = weight / <%=VOLUMETRIC_WEIGHT_CONVERSION%>;
    }

    // asp:label is rendered as a span in HTML.  So to set the value, 
    //  have to set the inner HTML.
    lblVolume.innerHTML = volume;
}

The second function, ValidateItemWeight, just checks the user entered a numeric value between certain limits and displays an alert if they didn't.

The code above works since I'm just passing an integer into the function: OnChange="ValidateItemWeightAndSetVolume(0);", but that is only applicable to the first repeater item. If I modify it as follows the function doesn't run: OnChange="ValidateItemWeightAndSetVolume(<%# Container.ItemIndex %>);"

2
  • 1
    Maybe it's the syntax of the OnChange line. See this answer. stackoverflow.com/a/14256670/3585500 Commented Nov 25, 2015 at 0:54
  • @OurManDave: That did the trick, thanks. Would you like to make it an answer? If so I'll mark it as accepted. Commented Nov 25, 2015 at 1:20

1 Answer 1

1

You can use <%# Container.ItemIndex %> as ourmandave suggested in the comment:

... OnChange="ValidateItemWeightAndSetVolume(<%# Container.ItemIndex %>`);" />

But it would be better if you could use javascript to get the label (instead of index concat with string-id) like this (jQuery):

Use OnChange = ValidateItemWeightAndSetVolume(this) and change the js function like this:

function ValidateItemWeightAndSetVolume(textBox) {    
    var txtWeight = textBox;
    var lblVolume = $(textBox).closest("td").next("td").find("span")[0];
    var volume = 0;
    var validated = ValidateItemWeight(txtWeight);
    if (validated) {
        var weight = parseFloat(txtWeight.value);
        volume = weight / <%=VOLUMETRIC_WEIGHT_CONVERSION%>;
    }

    lblVolume.innerHTML = volume;
}

Also, you can use a HeaderTemplate and FooterTemplate inside a Repeater like this:

<asp:Repeater ID="rptItems" runat="server">
    <HeaderTemplate>
        <table class="DataGrid">
            <tr class="HeaderStyle">
                <td>Item</td>
                <td>Weight (kg)</td>
                <td>Total Volume (m3):</td>
            </tr>
    </HeaderTemplate>
    <ItemTemplate>
        <!-- Your item template here -->
    </ItemTemplate>
    <FooterTemplate>
        </table>
    </FooterTemplate>
</asp:Repeater>

This keeps the mark-up clean imo.

Sign up to request clarification or add additional context in comments.

1 Comment

I'm not so keen on walking through the structure of the document to find the volume label, in case the structure changes. I would rather inject the ClientIDs via a server-side script block (inside <%...%> tags). The link in the comment by OurManDave helped me work out the correct syntax to inject the ClientIDs. However, your method works so may be useful for others.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.