読者です 読者をやめる 読者になる 読者になる

1.21 jigowatts

Great Scott!

ASP.NET ReadonlyのTextBoxをjQueryで変更した場合、サーバー側で値が取得できない

本日のバグ ASP.NET

概要

新年早々バグ修正しました。ReadonlyのTextBoxサーバコントロールはjQueryで見た目だけ変更してもサーバー側では値が取得出来ないので、見た目と違う値が登録されてしまいました。しかもシステム的に特殊なオペレーションを行った場合のみ出現するので見逃されていたようです。

環境

Visual Studio 2010
ASP.NET
.NET Framework 4

数量、金額を入力するとjQueryによりReadonlyのTextBox合計値が計算され表示されます。
f:id:sh_yoshida:20160120165721p:plain

保存ボタンを押下してサーバー側に処理が移った際、合計値は計算後ではなく初期値"0"が取得されます。
f:id:sh_yoshida:20160120165726p:plain

■Bug001.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Bug001.aspx.cs" Inherits="TodaysBugs.Bug001" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Bug001</title>
    <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Label ID="Label1" runat="server" Text="数量" Width="50px"></asp:Label>
            <asp:TextBox ID="txtQuantity" runat="server"></asp:TextBox>
            <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" 
                ErrorMessage="必須" ControlToValidate="txtQuantity" Display="Dynamic" 
                ForeColor="Red"></asp:RequiredFieldValidator>
            <asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" 
                ErrorMessage="数値を入力してください。" ValidationExpression="^[0-9]+$" 
                ControlToValidate="txtQuantity" Display="Dynamic" ForeColor="Red"></asp:RegularExpressionValidator>
        </div>
        <div>
            <asp:Label ID="Label2" runat="server" Text="金額" Width="50px"></asp:Label>
            <asp:TextBox ID="txtAmount" runat="server"></asp:TextBox>
            <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" 
                ErrorMessage="必須" ControlToValidate="txtAmount" Display="Dynamic" 
                ForeColor="Red"></asp:RequiredFieldValidator>
            <asp:RegularExpressionValidator ID="RegularExpressionValidator2" runat="server" 
                ErrorMessage="数値を入力してください。" ValidationExpression="^[0-9]+$" 
                ControlToValidate="txtAmount" Display="Dynamic" ForeColor="Red"></asp:RegularExpressionValidator>
        </div>
        <div>
            <asp:Label ID="Label3" runat="server" Text="合計" Width="50px"></asp:Label>
            <asp:TextBox ID="txtTotal" runat="server" ReadOnly="true" BackColor="Gray">0</asp:TextBox>
        </div>
        <div>
            <asp:Button ID="btnSave" runat="server" Text="保存" onclick="btnSave_Click" />
            <asp:Label ID="lblResult" runat="server" Text=""></asp:Label>
        </div>
        <div>
            <asp:Button ID="btnClear" runat="server" Text="クリア" onclick="btnClear_Click" />
        </div>
    </form>
</body>
<script language="javascript" type="text/javascript">
    $(function () {
        $('#<%= txtQuantity.ClientID%>').focusout(function (e) {
            setTotal();
        });
        $('#<%= txtAmount.ClientID%>').focusout(function (e) {
            setTotal();
        });
    });
    function setTotal() {
        var total = $('#<%= txtQuantity.ClientID%>').val() * $('#<%= txtAmount.ClientID%>').val();
        $('#<%= txtTotal.ClientID%>').val(total);
    }
</script>
</html>

■Bug001.aspx.cs

using System;

namespace TodaysBugs
{
    public partial class Bug001 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //aspx側のReadOnly属性は"false"にする
            //txtTotal.Attributes.Add("readonly", "true");
        }

        protected void btnSave_Click(object sender, EventArgs e)
        {
            var total = txtTotal.Text;
            lblResult.Text = "登録しました。 → 合計値:" + total.ToString();
        }

        protected void btnClear_Click(object sender, EventArgs e)
        {
            txtQuantity.Text = string.Empty;
            txtAmount.Text = string.Empty;
            txtTotal.Text = "0";
            lblResult.Text = string.Empty;
        }
    }
}

対応

Readonly属性を後から付与するとサーバー側でも合計値が計算後の値が取得できるようですが、今回はシンプルに数量と金額のTextBoxの値を取得し、サーバー側で再計算するよう修正することで対応しました。

参考

TextBox.ReadOnly プロパティ
TextBox.ReadOnly プロパティ (System.Web.UI.WebControls)