[ASP.NET]ListView使用jQuery計算Row與Column的值
前言
大家應該也會頗常碰到這樣的需求:當ListView或GridView等以table呈現資料時,每一格值改變時,需透過一定的公式計算出其他格的值,例如列或欄的總和。而且是不准postback的,要透過JavaScript來連動。
偏偏,這種東西又很常是跟錢有關,倒楣一點還帶著小數點(公式嘛…),這時候用JavaScript來算錢,就挺麻煩的了。黑大的名言:『算錢用浮點,遲早被人扁』,JavaScript預設就是使用floating。加上公式這種東西,又很有可能會改變或增加其他條件,或是在其他地方也用的到,所以我們面對這樣的環境時,我們期望可以將數值的處理寫在server端。
Solution
這邊的例子,我們透過ListView呈現資料,透過.ashx來執行公式並回傳結果,透過jQuery來定位row與column,以及呼叫ajax。
需求很單純:
- 將PayByMonth的值,乘上12後,放在Year欄位。
- 最後一列,有每一欄的總和。
- 每個數字的異動,都要將計算完相關的數值填回來。
Tips:
- 公式的部分放到.ashx裡面,透過jQuery的ajax來處理
- ajax是非同步的處理,所以我們最後一列的總和計算,應該要等每一列都確定算完了,才可以算。(這邊我是在算year時,將async設定成false了。 )
- 同一欄的所有input的class都一樣,我們則透過each來算column total
- 要定位同一列的不同input,則透過while loop,一直找parent,直到找到TR的tag後,再透過find(selector)來找這一列上,我們要定位的input。
- 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 + "¤tValue=" + 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的屬性與樣式。
畫面
結論
這篇文章只是描述一下,怎麼使用jQuery去尋找同一列上的input,怎麼透過.ashx來計算數值。我沒有花時間把JavaScript的部分寫的很漂亮,請見諒。透過這幾個tips實作的過程,相信未來需求異動時,各位也會知道如何去修改自己的code,來達到同樣的目的。
Sample Code: ListViewJavaScriptInterAction.zip
blog 與課程更新內容,請前往新站位置:http://tdd.best/