QA@IT

ASP.NET GridViewコントロールの行列固定後、JavaScriptのgetElementById(GridView)でnullが返る

8471 PV

Grid.jsとGrid.cssを使用し、GridViewコントロールの行列固定を行いました。
その後、GridView内のTextBoxのonchangeイベントでJavaScriptの関数を実行しているのですが、その関数の中のgetElementById(GridView)でnullが返ってきてしまいます。
コードは以下の様になっています。

[.aspx]

<head runat="server">
    <title></title>
    <script src="Scripts/Grid.js" type="text/javascript"></script>
    <link href="Styles/Grid.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript">
        //GridView行列固定関数
        window.onload = function () {
            var tableGridView = 
                document.getElementById("<%=GridView1.ClientID%>");
            var parentElement = tableGridView.parentNode;
            parentElement.setAttribute("id", "myGrid");
            parentElement.setAttribute("class", "style1");

            new Grid("myGrid", {
                srcType: "dom",
                srcData: "<%=GridView1.ClientID%>",
                allowGridResize: true,
                allowColumnResize: true,
                allowSelections: true,
                allowMultipleSelections: true,
                showSelectionColumn: false,
                fixedCols: 1
            });
        };
        //問題が起きている関数
        function aaa() {
            //gridにnullが返る
            var grid = document.getElementById("<%=GridView1.ClientID%>");
            ~略~
        }
   </script> 
    <style type="text/css">
        .style1
        {
            width: 400px;
            height: 360px;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
        <asp:GridView ID="GridView1" runat="server" EnableViewState="False" 
          OnRowCreated="GridView1_RowCreated" AutoGenerateColumns="False">
            <Columns>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:TextBox ID="TextBox1" runat="server" onchange="aaa()"></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:TextBox ID="TextBox2" runat="server" onchange="aaa()"></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:TextBox ID="TextBox3" runat="server"></asp:TextBox>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>
    </form>
</body>

最終的にaaa()でやりたいこととしては、GridView1内のTextBox1とTextBox2に入力した値を足しTextBox3に入力することです。
getElementById()でnullが返ってきてしまうとTextBoxの値が取得できなくて困っています。
解決策を教えていただけないでしょうか。
よろしくお願いいたします。

  • 先のスレッドで参照されていた私のブログを読まれたでしょうか? 「GridView が生成した table の DOM は、Grid.js が生成した別テーブルに置き換えられます。つまり、上の画像に表示されているテーブルは GridView ではなく、Grid.js が生成した別物です。 」と書きましたが。 -
  • IE を使っているなら F12 開発者ツールで見てください。GridView は存在しているでしょうか? -

回答

ブラウザはIEなので開発者ツールで確認したところGridViewではなくtableでした。

タイミングの問題で F12 開発者ツールでうまく見れないこともあるようです。

その table は ASP.NET が GridView から生成したもので(Grid.js が生成したものではなくて)、Grid.js による置き換えがうまく行っていれば、実際は存在していないはずです。(開発者ツールではうまく見れてないだけ)

質問者さんのコードでいうと、new Grid(...) の時点では table は存在しますが、function aaa() が動く時点では、table は new Grid(...) で生成された div 要素に置き換えられていて、実際には存在していないので、document.getElementById では取得できないということだと思います。

参考にされていた私のブログの「実験室」のリンク先のページを F12 開発者ツールで見ていただければ、GridView から生成された table は存在せず、div 要素で構成される全く別物に置き換えられているのが分かると思います。

なので直接TextBoxのidを指定し入力値を取得するようにしました。

document.getElementById で GridView から生成された table が取得できないにもかかわらず、GridView 内に配置した TextBox が取得できる(ように見える)のは、その TextBox から生成された input 要素が、id 等の属性を含めて、Grid.js が生成した div 要素の中にそのままコピーされるからです。

それで JavaScript は動くと思いますが、問題があるとすると、この先 GridView の Template に配置した TextBox の ClientID の命名規則が変わらないという保証がないということです。

命名規則は変わらないとしても、保守の際など何かの都合で TextBox の ID を変えると JavaScript のコードも書き換えなければならないという面倒なこともあります。

そういう問題を回避できるように、function aaa(own) の書き方を検討されることをお勧めします。(例えば、引数に ClientID を渡すなど)

編集 履歴 (0)
  • tableが無くなる様子を開発者ツールで見ることはできませんでしたが、そのようになっているんですね。とても勉強になります。aaa()の中身ももう少し検討していきます。アドバイスありがとうございます。Grid.cssについてなのですが、どのクラスがどの部分に対応しているというのは英語のコメントから判断するしかないのでしょうか。 -
  • Grid.css のどのクラスがどの部分に対応しているかは、F12 開発者ツール上に Grid.js が生成した div 要素が表示できれば、すぐ分かります。使い方は「F12 開発者ツール」をキーワードにググれば見つかるはずです。 -
  • ありがとうございます。
    開発者ツールの使い方から調べてみます。
    -

SurferOnWwwさん、ありがとうございます。
理解していなくて申し訳ありません。
ブラウザはIEなので開発者ツールで確認したところGridViewではなくtableでした。
なので直接TextBoxのidを指定し入力値を取得するようにしました。
下記のようにしました。
[関数側]

function aaa(own) {
    var idSplit = own.id.split("_");
    var rowNum = Number(idSplit[2]);    // 自身のidから行数を取得
    var total = 0;
    // TextBox1,2の合計値を計算
    for (var i = 1; i < 3; i++) {
        var tb = document.getElementById("GridView1_TextBox" + i + "_" + rowNum);
        if (tb.value != "") {
            total += Number(tb.value);
        }
    }
    var tb3 = document.getElementById("GridView1_TextBox3_" + rowNum);
    tb3.value = total;  // 合計列へ入力    
}

[呼び出し側]

<asp:GridView ID="GridView1" runat="server" EnableViewState="False" 
  OnRowCreated="GridView1_RowCreated" AutoGenerateColumns="False">
    <Columns>
    <asp:TemplateField>
        <ItemTemplate>
            <asp:TextBox ID="TextBox1" runat="server" onchange="aaa(this)"></asp:TextBox>
        </ItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField>
        <ItemTemplate>
            <asp:TextBox ID="TextBox2" runat="server" onchange="aaa(this)"></asp:TextBox>
        </ItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField>
        <ItemTemplate>
            <asp:TextBox ID="TextBox3" runat="server"></asp:TextBox>
        </ItemTemplate>
    </asp:TemplateField>
    </Columns>
</asp:GridView>

SurferOnWwwさんの回答にacceptしたいのですが、どうすればよいでしょうか?

編集 履歴 (1)
ウォッチ

この質問への回答やコメントをメールでお知らせします。