0

I have a GridView with a column where I enter numbers. A Javascript sums these numbers as I type them in and shows the total in a Label outside the GridView. Works fine.

Somewhere on the the page there's a button that causes a postback when clicked, and in order not to loose the value of the Total label, the Javascript also saves the total in a HiddenField, and on page_load I copy it from the HiddenField back to the Total label. That works too.

But...if after I am back from the postback and I type a number in any of the cells, the Total would reflect only that number and ignore the values in all other cells. Those are lost between postbacks.

I guess the Javascript should keep not only the Total label but all values of all cells in that column, but my knowledge of JS is close to zero (for now...).

My HTML :

     <table>
        <tr>
            <td>
                <asp:Button ID="btn" runat="server" OnClick="btn_Click" Text="Click me" />
                <asp:Label ID="lbl_Message" runat="server"></asp:Label>
            </td>
        </tr>
        <tr>
            <td>
                <div>
                    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
                        <Columns>
                            <asp:BoundField DataField="Something" HeaderText="Something" />
                            <asp:TemplateField HeaderText="Payed">
                                <ItemTemplate>
                                    <asp:TextBox ID="txb_Payed" runat="server"></asp:TextBox>
                                </ItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField HeaderStyle-CssClass="myHidden" ItemStyle-CssClass="myHidden">
                                <ItemTemplate>
                                    <asp:Label ID="lbl_Temp_Payed" runat="server" Text="0"></asp:Label>
                                </ItemTemplate>
                            </asp:TemplateField>
                        </Columns>
                    </asp:GridView>
                    Grand Total:
                            <asp:Label ID="lbl_Grand_Total" runat="server" Text="0"></asp:Label>
                    <asp:HiddenField ID="hdf_Keep_Total" runat="server" />
                </div>
            </td>
        </tr>
    </table>

My Javascript:

<script type="text/javascript">
    $("[id *= txb_Payed]").live("change", function () {
        if (isNaN(parseInt($(this).val()))) {
            $(this).val('0');
        } else {
            $(this).val(parseInt($(this).val()).toString());
        }
    });
    $("[id *= txb_Payed]").live("keyup", function () {
        if (!jQuery.trim($(this).val()) == '') {
            if (!isNaN(parseFloat($(this).val()))) {
                var row = $(this).closest("tr");
                $("[id *= lbl_Temp_Payed]", row).html(parseFloat($(this).val()));
            }
        } else {
            $(this).val('');
        }
        var my_Total = 0;
        $("[id *= lbl_Temp_Payed]").each(function () {
            my_Total = my_Total + parseFloat($(this).html());
        });
        $("[id *= lbl_Grand_Total]").html(my_Total.toString());
        var my_hdf_Keep_Total = '<%= hdf_Keep_Total.ClientID %>';
            document.getElementById(my_hdf_Keep_Total).value = my_Total;
        });
</script>

My C# code-behind:

    protected void Page_Load(object sender, EventArgs e)
    {
        lbl_Grand_Total.Text = hdf_Keep_Total.Value;
        if (!Page.IsPostBack)
        {
            Bind_Sample_Data_To_Grid();
        }
    }
    private void Bind_Sample_Data_To_Grid()
    {
        DataTable dt = new DataTable();
        dt.Columns.AddRange(new DataColumn[1] { new DataColumn("Something") });
        dt.Rows.Add("aaaaa");
        dt.Rows.Add("bbbbb");
        dt.Rows.Add("ccccc");
        GridView1.DataSource = dt;
        GridView1.DataBind();
    }
    protected void btn_Click(object sender, EventArgs e)
    {
        lbl_Message.Text = "U clicked";
    }

(The Javascript is probably terribly inefficient and messy because I just copy stuff I find on the net without really understanding it. Any remark on that code would be very beneficial to me too).
EDIT :
This page is intended to end up as a receipt where the user (the one producing the receipt) will enter one or more numbers at the proper cell in the gridview row, and the application needs to sum these numbers so the user can see the total as he types in the numbers. In the row there will be more rows with more information. I simplified it to the minimum for the purpose of opening this Q.
(the term 'Quantity' in the code was misleading and I changed it to 'Payed'. Also, as @Fnostro suggested, I took out the UpdatePanel from the page).
This is what I get at first:
enter image description here
I then enter 45 at the 1st row and as I type it I see the total being updated to 45. I enter 30 and the total is immediately updated to 75 :
enter image description here
I then click the Button, and get :
enter image description here
Now I place the cursor on the last row and enter 5 and the total shows 5 as well. The Javascript ignores the other two values:
enter image description here
I hope I was clearer now and would appreciate any help.

gadi
  • 481
  • 3
  • 14
  • 32
  • I am not very familiar with jQuery but I think that the answer to your question is in this post: http://stackoverflow.com/questions/256195/jquery-document-ready-and-updatepanels – ConnorsFan Mar 27 '16 at 22:12
  • @ConnorsFan - thanks 4 the link. Tried it before posting my question, but that did not help. – gadi Mar 28 '16 at 18:55
  • Question related to fnostro's answer: does it work without the UpdatePanel? And just to be sure: are the fields empty after the postback or just ignored in the calculation of the total? – ConnorsFan Mar 28 '16 at 19:09
  • In fact, the button is supposed to add a row in the GridView. That's why I need to keep the values between postbacks which occur when clicking the button. As I said - I simplified things here to the minimum. – gadi Mar 29 '16 at 19:28
  • I was just wondering if the fields were cleared after the postback, or if the values were there but the calculation function did not "see" them. I now understand that the fields are empty. – ConnorsFan Mar 29 '16 at 19:33
  • you're losing the values on each postback because the DataTable is dynamic. You need to create the DataTable once and persist it either in the ViewState, Session state, or a backing database. – fnostro Mar 30 '16 at 00:14

1 Answers1

1

I have a GridView (inside an UpdatePanel) with a column where I enter numbers.

I would not introduce an UpdatePanel until you have the code working without it. Partial page postbacks affect JS/JQ and you have to know how to handle that. When dealing with UpdatePanels I use JS/JQuery code similar to this:

// Handle Full Postback
$( function() {
    FullAndPartialPostback_EventHandler( true, null, null );
} );

// Handle Partial Postback
Sys.WebForms.PageRequestManager.getInstance().add_endRequest( function( sender, args ) {
    FullAndPartialPostback_EventHandler( false, sender, args );
} );


function FullAndPartialPostback_EventHandler( isFullPostBack, sender, args ) {
    // Do stuff common to both Full/Partial postbacks here 

    if( isFullPostBack ){
        // Do Full postback specific stuff here
    }
    else {
        // Do Partial postback specific stuff here
    }

    // Do more stuff common to both here 
}

In the above code, I replace the prefix text, FullAndPartialPostback with the page (or user control) class name so it reads something like Default_EventHandler and it's clear to which class this handler belongs.

A Javascript sums these numbers, as I type them in, and shows the total in a Label outside the GridView. Works fine. Somewhere on the the page there's a button that causes a postback when clicked,

Most Every ASP.NET server control button causes a postback. You kept the UpdatePanel defaults, so leaving ChildrenAsTriggers=true means buttons will post back.

and in order not to loose the value of the Total label, the Javascript also saves the total in a HiddenField, and on page_load I copy it from the HiddenField back to the Total label. That works too.

That's good - HiddenFields are good for that, however...

But...if after I am back from the postback and I type a number in any of the cells, the Total would reflect only that number and ignore the values in all other cells. Those are lost between postbacks.

Are the numbers literally lost or added to the previous total? If the textbox values are preserved, you don't need to save the total - just recalc. If they are lost then preserving the Total has no meaning.

Without knowing your final goal, I don't have any advice on how best to proceed. Typically you don't post client side JS/JQ calculated data if all the source data ends up being posted back to the server, just recalculate the total on the server side.

Addendum 2016-02-29: Explanation Follows Snippet

var $GrandTotal = null;
var $InputFields = null;

$(function() {
  $GrandTotal = $(".GrandTotal");
  $InputFields = $(".InputField");
  
  $InputFields.on("keyup", SumRows);

  SumRows();
});

function SumRows() {
  var SubTotal = 0.0;
  
  $InputFields.each( function(){
    if( $.isNumeric($(this).val() ) )
      SubTotal += parseFloat($(this).val());
  });
  
  $GrandTotal.text(SubTotal);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
  <thead>
    <tr><td>Something</td><td>Payed</td></tr>
  </thead>
  <tbody>
    <tr><td>aaaaa</td><td><input id="tbx_Payed_1" class="InputField" type="number"></td></tr>
    <tr><td>bbbbb</td><td><input id="tbx_Payed_2" class="InputField" type="number"></td></tr>
    <tr><td>ccccc</td><td><input id="tbx_Payed_3" class="InputField" type="number"></td></tr>
    <tr><td>ddddd</td><td><input id="tbx_Payed_4" class="InputField" type="number"></td></tr>
  </tbody>
  <tfoot>
    <tr><td>Sum</td><td><span id='lbl_Grand_Total' class="GrandTotal" >0</span></td></tr>
  </tfoot>
</table>

Server controls are posted back on every post. The same applies to fields contained within a Gridview. The trick is to not overwrite the input fields with bound data.

You should not need a hidden field to hold the grand total as it can easily be recalculated after ever postback.

It's also worth noting the use of "anonymous classes." The classes GrandTotal and InputField are not defined styles in any CSS, although they can be. But they are used here to simplify finding the fields jquery needs to do the calculation. This is far easier that trying to figure out what kind of mangling ASP.NET is going to do to the Control ID's. You should rarely, if ever, need to use *=, e.g.: $("input[id*='some_id']") to find a field.

Since all the inputs and calculations are contained within server controls there is no need to use Hidden fields as the server controls will preserve their values during the round trip and the summation can be easily redone on the client side once the page is loaded.

FYI: jquery's live() function is deprecated.

fnostro
  • 4,531
  • 1
  • 15
  • 23
  • thanks for your time. But your snippet does not have a postback in it. It's a different way to code what I already have. My app will have a button to add a row in the gridview, which will cause a postback. What I'm looking for is a way to preserve the 'summing' functionality between postbacks. – gadi Apr 04 '16 at 09:40