Search code examples
javascriptjqueryasp.netlistview

asp.net textbox clientside lost focus event in listview control


I have below lines of code in asp:list view control, if user input any value on 2nd text box, on client side lost focus event I need to calculate txtTokensReq * txtQty and display in lblTotalTokens.

 <asp:ListView runat="server" ID="lstView" ClientIDMode="Static" GroupItemCount="1" OnItemDataBound="lstView_ItemDataBound">

<asp:TextBox runat="server" CssClass="inputQty" MaxLength="5" ID="txtTokensReq" ClientIDMode="Static" Text='<%# Eval("PartToken")%>' ReadOnly="true"></asp:TextBox>

<asp:TextBox runat="server" cssClass="inputQty" MaxLength="5" ID="txtQty" Text='<%# Eval("Qty")%>' onKeypress ="if(!validatenumeric(this,5)){return false;}"></asp:TextBox>

<asp:Label ID="lblTotalTokens" CssClass="note-maxqty col-last" Text='<%# Eval("TotalTokenReq")%>' runat="server"></asp:Label>

 </asp:ListView>

WHen I wrote onblur function on 2nd textbox, it is firing more than once.

Thanks in advance.


Solution

  • Ok, a few things.

    Inside of a list view, it does not make sense to set client id mode = "static", since the controls will be repeated over and over. Thus, if you use static for the id, then we wind up breaking the rules of HTML and multiple controls with the same id is not allowed.

    Controls in a ListView will be auto generated for each row, and they will look like this:

    ListView1_Qty_0
    ListView1_Qty_1
    ListView1_Qty_2
    . etc. for each new row
    

    And of course, if we want to use a selector for other controls on that ONE row of data, then once again, we will need to select each control based on above ("ListView Name" + "" + Control Name + "" + Row number.

    The above can be difficult, so I tend to create a JavaScript function, and we simple pass what the "base" control id was in the first place.

    And it not clear why you using onkey down, you should use onchange event, since that only triggers after the user tabs out of the control (or it loses focus).

    So, with this markup:

            <div style="width: 50%" id="myGridList">
                <asp:ListView ID="ListView1" runat="server" DataKeyNames="ID">
                    <ItemTemplate>
                        <tr>
                            <td>
                                <asp:TextBox ID="txtFirst" runat="server" Text='<%# Eval("FirstName") %>' Width="70px" /></td>
                            <td>
                                <asp:TextBox ID="txtLast" runat="server" Text='<%# Eval("LastName") %>' Width="70px" /></td>
                            <td>
                                <asp:TextBox ID="txtCity" runat="server" Text='<%# Eval("City") %>' Width="70px" /></td>
                            <td>
                                <asp:TextBox ID="txtHotelName" runat="server" Text='<%# Eval("HotelName") %>' Width="100px" /></td>
                            <td>
                                <asp:TextBox ID="txtDescription" runat="server" Text='<%# Eval("Description") %>'
                                    TextMode="MultiLine" Columns="52" />
                            </td>
                            <td style="text-align: right">
                                <asp:TextBox ID="txtNights" runat="server" Text='<%# Eval("Nights") %>' Width="35px"
                                    onchange="jcalc(this,'txtNights')" />
                            </td>
                            <td style="text-align: center">
                                <asp:TextBox ID="txtPerNight" runat="server" Text='<%# Eval("NightRate", "{0:C0}") %>' Width="40px" 
                                    onchange="jcalc(this,'txtPerNight')" />
                            </td>
                            <td style="text-align: right">
                                <asp:Label ID="txtPrice" runat="server"
                                    Text='<%# Eval("Price", "{0:C2}") %>' />
                            </td>
    
                            <td style="text-align: center">
                                <button id="cmdDelete" runat="server" class="btn"
                                    onserverclick="cmdDelete_ServerClick" tabindex="-1"
                                    onclick="if (!confirm('Really delete')) {return false}">
                                    <span aria-hidden="true" class="glyphicon glyphicon-trash"></span>
                                </button>
                            </td>
                        </tr>
                    </ItemTemplate>
                    <LayoutTemplate>
                        <table id="itemPlaceholderContainer" runat="server"
                            class="table  table-hover table-bordered table-striped borderhide">
                            <tbody>
                                <tr runat="server" style="">
                                    <th runat="server" style="width: 60px">First</th>
                                    <th runat="server" style="width: 60px">Last</th>
                                    <th runat="server" style="width: 60px">City</th>
                                    <th runat="server" style="width: 70px">Hotel Name</th>
                                    <th runat="server" style="width: 140px">Description</th>
                                    <th runat="server" style="width: 60px">Nights</th>
                                    <th runat="server" style="width: 60px">Per<br />
                                        Night</th>
                                    <th runat="server" style="width: 60px">Amount</th>
                                    <th runat="server" style="width: 60px"></th>
                                </tr>
                                <tr id="itemPlaceholder" runat="server">
                                </tr>
                            </tbody>
                            <tfoot>
                                <tr>
                                    <%-- skip 6 boxes --%>
                                    <td></td>
                                    <td></td>
                                    <td></td>
                                    <td></td>
                                    <td></td>
                                    <td></td>
    
                                    <td style="text-align: right">Total</td>
                                    <td style="text-align: right">
                                        <asp:Label ID="lblTotalSum" runat="server" Width="62px" ClientIDMode="Static">
                                        </asp:Label>
                                    </td>
                                </tr>
                            </tfoot>
                        </table>
                    </LayoutTemplate>
                </asp:ListView>
    
            </div>
    
            <button id="cmdSave" runat="server" class="btn"
                onserverclick="cmdSave_Click" tabindex="-1">
                <span aria-hidden="true" class="glyphicon glyphicon-share">Save&ensp;/&ensp;Update</span>
            </button>
    
            <button id="cmdAddNew3" runat="server" class="btn" style="margin-left: 20px"
                onserverclick="cmdAddNew_Click" tabindex="-1">
                <span aria-hidden="true" class="glyphicon glyphicon-plus-sign">New&ensp;Hotel</span>
            </button>
    
            <button id="cmdUnDo" runat="server" class="btn" style="margin-left: 20px"
                onserverclick="cmdUnDo_ServerClick" tabindex="-1">
                <span aria-hidden="true" class="glyphicon glyphicon-retweet">Undo</span>
            </button>
    
        </div>
    
        <script>
            function jcalc(ctl, tid) {
    
               // simple grid update price from nights X rate
                var Nights = $('#' + ctl.id.replace(tid, 'txtNights'))
                var Price = $('#' + ctl.id.replace(tid, 'txtPerNight'))
                var tAmount = $('#' + ctl.id.replace(tid, 'txtPrice'))
    
                var MyPrice = Nights.val() * DollarToNum(Price.val())
                tAmount.text(NumToDollar(MyPrice))
    
                // change save button to blue - shows edits were done
                $('#cmdSave').addClass('btn btn-info')
    
                // total up colum for display
    
                var myGrid = $("#myGridList")                   // select list view area (div)
                myTotalcols = myGrid.find("[id *= txtPrice]")   // select txtPrice from list view
                var myTotal = 0;
                myTotalcols.each(function () {
                    myvalue = DollarToNum(this.innerText)
                    myTotal += myvalue});
    
                $('#lblTotalSum').text(NumToDollar(myTotal))    // control in footer
            }
    
    
            function DollarToNum(sValue) {
                // take sring currency such as $12,555,00 and conver to number
                return Number(sValue.replace(/[^0-9.-]+/g, ""))
            }
    
            function NumToDollar(sValue) {
                // take number and convert to string with currency format
                var dollarUSLocale = Intl.NumberFormat('en-US',
                    { style: "currency", currency: "USD", useGrouping: true, minimumFractionDigits: 2 })
                var resultamount = 0
                return dollarUSLocale.format(sValue)
            }
        </script>
    

    Note how I wrapped the ListView in a div with an id, so I select that out of the page. (after all, you might have more then one ListView on the page).

    And note how I simply pass the "base" control id with the JavaScript function. Since there is that "row" naming process for each row, then I just replace the text of the values I want based on the current control's id (which will include that row number and control name).

    I also show how I can select each row using a wild card jQuery selector, and I used that to total up the resulting values, and place that into a footer control.

    So, the result looks like this:

    enter image description here

    So, I suggest removing the ClientIDMode for controls in the ListView, since they are going to repeat, and you lose practical means to select controls from a given row.