[ASP.NET]ListView使用jQuery計算Row與Column的值

  • 8836
  • 0

[ASP.NET]ListView使用jQuery計算Row與Column的值

前言
大家應該也會頗常碰到這樣的需求:當ListView或GridView等以table呈現資料時,每一格值改變時,需透過一定的公式計算出其他格的值,例如列或欄的總和。而且是不准postback的,要透過JavaScript來連動。

偏偏,這種東西又很常是跟錢有關,倒楣一點還帶著小數點(公式嘛…),這時候用JavaScript來算錢,就挺麻煩的了。黑大的名言:『算錢用浮點,遲早被人扁』,JavaScript預設就是使用floating。加上公式這種東西,又很有可能會改變或增加其他條件,或是在其他地方也用的到,所以我們面對這樣的環境時,我們期望可以將數值的處理寫在server端。

Solution
這邊的例子,我們透過ListView呈現資料,透過.ashx來執行公式並回傳結果,透過jQuery來定位row與column,以及呼叫ajax。

需求很單純:

  1. 將PayByMonth的值,乘上12後,放在Year欄位。
  2. 最後一列,有每一欄的總和。
  3. 每個數字的異動,都要將計算完相關的數值填回來。


Tips:

  1. 公式的部分放到.ashx裡面,透過jQuery的ajax來處理
  2. ajax是非同步的處理,所以我們最後一列的總和計算,應該要等每一列都確定算完了,才可以算。(這邊我是在算year時,將async設定成false了。 )
  3. 同一欄的所有input的class都一樣,我們則透過each來算column total
  4. 要定位同一列的不同input,則透過while loop,一直找parent,直到找到TR的tag後,再透過find(selector)來找這一列上,我們要定位的input。
  5. document.ready()以及各input change的時候 都要重算資料

 

說完了,我們來看一下code怎麼寫
.aspx:


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>    
    <style type="text/css">
        .readonlyStyle
        {
            background-color: #999999;
        }
        
    </style>
    <script type="text/javascript">
        $(document).ready(function () {            
            var eachMonthClass = '.EachMonth';
            var eachYearClass = '.EachYear';
            var totalMonthClass = '.TotalMonth';
            var totalYearClass = '.TotalYear';

            $(eachMonthClass).each(function () {
                $(this).val(ConvertEmptyToZero($(this).val()));
                calRowTotal($(this), eachMonthClass, eachYearClass);
            })
            .bind('change', function () {
                if (!isNaN($(this).val())) {
                    $(this).val(Number($(this).val()));
                }
                calRowTotal($(this), eachMonthClass, eachYearClass);

                calColumnTotal(eachMonthClass, totalMonthClass);
                calColumnTotal(eachYearClass, totalYearClass);

            });

            calColumnTotal(eachMonthClass, totalMonthClass);
            calColumnTotal(eachYearClass, totalYearClass);

            //套readonly或對應的唯讀css            
            $(totalMonthClass).add(totalYearClass).add(eachYearClass).addClass('readonlyStyle');
            $('.readonlyStyle').attr('readonly', 'readonly');
        });

        function calRowTotal(obj, itemClass, totalClass) {
            var columnEachMonth = itemClass;
            var columnEachYear = totalClass;

            while (obj.attr('tagName') != 'TR') {
                obj = obj.parent();
            }

            var eachMonth = ConvertEmptyToZero(obj.find(columnEachMonth).val().replace(/,/g, ''));
            $.ajax({
                async: false,
                url: 'Calculate.ashx',
                type: 'post',
                data: "mode=calculateYear&eachMonth=" + eachMonth,
                success: function (result) {
                    obj.find(columnEachYear).val(result);
                }
            });            
        }

        function ConvertEmptyToZero(originalValue) {
            if (originalValue == '') { originalValue = 0; }
            return Number(originalValue);
        }

        function calColumnTotal(columnClass, totalClass) {
            var total = 0;
            var columnSelector = columnClass;
            var totalSelector = totalClass;
            $(columnSelector).each(function (i) {
                
                var currentValue = $(this).val().replace(/,/g, '');
                
                currentValue = ConvertEmptyToZero(currentValue);

                if (!isNaN(currentValue)) {
                    //total = Number(total) + Number(currentValue);
                    $.ajax({
                        async: false,
                        url: 'Calculate.ashx',
                        type: 'post',
                        data: "mode=calculateTotal&total=" + total + "&currentValue=" + currentValue,
                        success: function (result) {
                            total = result;
                        }
                    });
                }

            });
            $(totalSelector).val(total);
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>    
        <asp:ListView ID="ListView1" runat="server">
            <LayoutTemplate>
                <table id="tbLvHeader" runat="server" class="grid" cellpadding="0" cellspacing="0"
                    style="empty-cells: show;">
                    <tr class="head">
                        <th>
                            ID
                        </th>
                        <th>
                            PayByMonth
                        </th>
                        <th>
                            Year=Month x 12
                        </th>
                    </tr>
                    <tr id="itemPlaceholder" runat="server">
                    </tr>
                    <tr id="endPlaceholder" runat="server" class='<%# ListView1.Items.Count % 2 == 0 ? "row" : "altrow" %>'>
                        <td>
                            <asp:Label ID="Label4" runat="server" Text="總金額"></asp:Label>
                        </td>
                        <td>
                            <asp:TextBox ID="txtByMonth" runat="server" CssClass="TotalMonth"></asp:TextBox>
                        </td>
                        <td>
                            <asp:TextBox ID="txtByYear" runat="server" CssClass="TotalYear"></asp:TextBox>
                        </td>
                    </tr>
                </table>
            </LayoutTemplate>
            <ItemTemplate>
                <tr id="row" runat="server" class='<%# Container.DataItemIndex % 2 == 0 ? "row" : "altrow" %>'>
                    <td>
                        <%# Eval("ID")%>
                    </td>
                    <td>
                        <asp:TextBox ID="txtByMonth" runat="server" Text='<%# Eval("PayByMonth")%>' CssClass="EachMonth"></asp:TextBox>
                    </td>
                    <td>
                        <asp:TextBox ID="txtByYear" runat="server" Text='<%# Eval("PayByYear")%>' CssClass="EachYear"></asp:TextBox>
                    </td>
                </tr>
            </ItemTemplate>
        </asp:ListView>
    </div>
    </form>
</body>
</html>

.ashx


public class Calculate : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {

        string mode = Convert.ToString(context.Request.Form["mode"]);

        switch (mode)
        {
            case "calculateYear":
                string eachMonth = context.Request.Form["eachMonth"] as string;
                context.Response.Write(CalculateYear(eachMonth).ToString());
                break;
            case "calculateTotal":
                string total = context.Request.Form["total"] as string;
                string currentValue = context.Request.Form["currentValue"] as string;
                context.Response.Write( CalculateTotal(total, currentValue).ToString());
                break;       
            default:
                break;
        }        

    }
    private double CalculateYear(string eachMonth)
    {
        double month = Convert.ToDouble(eachMonth);
        return month * 12;
    }

    private double CalculateTotal(string total, string currentValue)
    {
        return Convert.ToDouble(total) + Convert.ToDouble(currentValue);
    }
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

}


by the way, 我有針對計算結果去設定readonly的屬性與樣式。

畫面

  1. 初始畫面
    image
  2. 改變Month值
    image

 

結論
這篇文章只是描述一下,怎麼使用jQuery去尋找同一列上的input,怎麼透過.ashx來計算數值。我沒有花時間把JavaScript的部分寫的很漂亮,請見諒。透過這幾個tips實作的過程,相信未來需求異動時,各位也會知道如何去修改自己的code,來達到同樣的目的。

Sample Code: ListViewJavaScriptInterAction.zip

 


blog 與課程更新內容,請前往新站位置:http://tdd.best/