質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.52%

Javascriptによるテーブル内の任意のセル内テキストの編集

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,571
HTMLとJavascriptで、テーブルのセル内のテキストをモーダルウィンドウ内で編集し、
編集後の内容を元のテキストと置き換えるスクリプトを作成しています。

・テーブル内の任意のセル内をクリックするとモーダルウィンドウが表示される
・モーダルウィンドウ内でテキストを編集し確定ボタンを押下すると、元のセルの内容を置換する
・モーダルウィンドウ内でキャンセルボタンを押下すると、ウィンドウを閉じる
・セルにIDを振ることはできない
・テーブルの行、列は任意に増やすことができる

以下のように作成したところ、編集を繰り返すごとに、それまで編集したセルが
すべて置き換わってしまいました。
セルをクリックする度に、対象のセルが累積していく様子です。

原因としては、テーブルセルのclickイベント内に保存ボタンのイベント処理が
あることだと思うのですが、外に出した場合、クリック元のセルを取得する方法が分かりません。

どなたか助けていただけないでしょうか。
jquery-1.7.2.js

$(function(){
    
    //テーブルセル押下で編集モード
    $('[id^=edit-table] > tbody > tr > td').on('click', function(){
    var targetCell = $(this);

        //disable-editorクラスがある場合は編集させない
        if(!$('[id^=edit-table]').hasClass('disable-editor')){
            html = targetCell.html();
            //エディタ起動
            var target = '#td_editor_modal';  //モーダルウィンドウのID
            activateTdEditor(target, html);  //モーダルウィンドウ表示

            //エディタウィンドウの保存ボタン
            $('#do-save').on('click',function(){
                //エディタ内のコンテンツを取得
                //本来はエディタからの戻り値が入る
                var content = 'ほげほげ'
                //モーダルウィンドウを閉じる
                modalClose('#td_editor_modal');
                //元のセルの内容を置換
                $(targetCell).html(content);
            });

            //エディタウィンドウを閉じる
            $('#modal-close').on('click', function(){
                modalClose('#td_editor_modal');
            });

        }

    });
});
<div id="table-edit-area">
        <table id="edit-table-hoihoi" class="table table-bordered">
                <tbody>
                        <tr>
                                <td>見出し1</td>
                                <td>見出し2</td>
                                <td>見出し3</td>
                        </tr>
                        <tr>
                                <td>1-1</td>
                                <td>1-2</td>
                                <td>1-3</td>
                        </tr>
                        <tr>
                                <td>2-1</td>
                                <td>2-2</td>
                                <td>2-3</td>
                        </tr>
                        <tr>
                                <td>3-1</td>
                                <td>3-2</td>
                                <td>3-3</td>
                        </tr>
                </tbody>
        </table>
</div>

<!-- セル内編集用ののモーダルウィンドウ -->
<div id="modal-overlay"></div>
<div id="td_editor_modal">
        <div id="edit_box"></div>

        <div class="btn-control">
                <button id="do-save" class="btn btn-primary">保存</button>
                <button id="modal-close" class="btn btn-primary">キャンセル</button>
        </div>
</div>

以下を追記いたしました。
/*-------------------------
*  エディタ起動
---------------------------*/
function activateTdEditor(target, html){
    //モーダルウィンドウ表示位置調整
    centeringModalPosition(target);
    //モーダルウィンドウ表示
    modalOpen(target);

    //エディタ起動
    $('#edit_box').html(html);
    //ダミーとして編集したことにする
    $('#edit_box').append('ああああああ');
}
/*-------------------------
*  モーダルウィンドウを開く
---------------------------*/
function modalOpen(modalId){
     $(modalId).css('display', 'block');
     $('#modal-overlay').css('display', 'block');
}

/*-------------------------
*  モーダルウィンドウを閉じる
---------------------------*/
function modalClose(modalId){
     $('#modal-overlay').css('display', 'none');
     $(modalId).css('display', 'none');
}

/*-------------------------
*  モーダルウィンドウの表示位置調整
---------------------------*/
function centeringModalPosition(modalId){
     //画面幅取得
     var w = $(window).width();
     //画面高さ取得
     var h = $(window).height();

     //モーダルウィンドウの幅取得
     var cw = $(modalId).outerWidth(true);
     //モーダルウィンドウの高さ取得
     var ch = $(modalId).outerHeight(true);


     //モーダルウィンドウの横位置計算
     var pxleft = ((w - cw)/2);
     //モーダルウィンドウの縦位置計算
     var pxtop = ((h - ch)/2);

     $(modalId).css({"left": pxleft + "px"});
     $(modalId).css({"top": pxtop + "px"});

}

function debugPrintIndex(e){
    //行番号取得
    var row = $(e.target).closest('tr').index();
    //列番号取得
    var col = e.target.cellIndex;

    console.log('行:列 = ' + row + ':' + col);
}

activateTdEditorも自由に変更可能です。
記載したソースではダミーの処理をしていますが、実際のコードでもさほど変わらず、エディタにセル内の値を食わせてエディタ起動しているだけです。

以下動作サンプルです。
●エディタなし版
http://amicolo.net/make-table/index4.html

●エディタあり版
http://amicolo.net/make-table/index5.html

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Lhankor_Mhy

    2015/10/24 17:59

    activateTdEditor を変更するのが一番簡単だと思うんですが、そちらは可能ですか?

    キャンセル

  • smiley-_-smiley

    2015/10/25 08:03 編集

    誤って返信のつもりで記載してしまいました。削除できないようなので、本文中に追記します

    キャンセル

回答 2

check解決した方法

0

自己解決しました。
クリックイベントを入れ子にした場合に、それまで操作したセルが全部処理される現象は
謎のままですが、とりあえず以下の方法で対応しました。

・クリックしたセルの座標を取得
・モーダルウィンドウ内の非表示要素に座標を文字列として格納
・保存時にウィンドウ内から座標文字列を取得し、対象セルの座標として指定

$(function(){
    //テーブルセル押下で編集モード
    $('[id^=edit-table] > tbody > tr > td').on('click', function(e){
    var targetCell, html, x, y, selector;
    
    console.log(targetCell);
        //disable-editorクラスがある場合は編集させない
        if(!$('[id^=edit-table]').hasClass('disable-editor')){
            html = $(this).html();
            console.log('セル内のHTML:'+html);

            //対象セル取得
            targetCell = getCurentCell(e);

            //エディタ起動
            var target = '#td_editor_modal';
            activateTdEditor(target, html, targetCell);
        }

    });

    //エディタウィンドウの保存ボタン
    $('#do-save').on('click',function(){    
    
        //エディタ内のコンテンツを取得
        //本来はエディタからの戻り値が入る
        var content = $('#edit_box').elrte('val');
        console.log('戻り値:'+content);

        //モーダルウィンドウを閉じる
        modalClose('#td_editor_modal');

        //対象セルを取得
        var targetCell = $('#targetCell').text();  // x-y で帰ってくる
        tmp = targetCell.split('-');
        var x = tmp[0];
        var y = tmp[1];
        selector = '[id^=edit-table] > tbody > tr:eq(' + x + ') > td:eq(' + y + ')';

        //元のセルの内容を置換
        $(selector).html(content);
    });

    //エディタウィンドウを閉じる
    $('#modal-close').on('click', function(){
        modalClose('#td_editor_modal');
    });


});

/*-------------------------
*  エディタ起動
---------------------------*/
function activateTdEditor(target, html, targetCell){
    //モーダルウィンドウ表示位置調整
    centeringModalPosition(target);
    //モーダルウィンドウ表示
    modalOpen(target);
    //クリックしたセルの座標を格納
    $('#targetCell').text(targetCell);

    //エディタ起動
    $('#edit_box').elrte(opts);
    $('#edit_box').elrte('val', html);
}

/*-------------------------
*  モーダルウィンドウを開く
---------------------------*/
function modalOpen(modalId){
     $(modalId).css('display', 'block');
     $('#modal-overlay').css('display', 'block');
}

/*-------------------------
*  モーダルウィンドウを閉じる
---------------------------*/
function modalClose(modalId){
     $('#modal-overlay').css('display', 'none');
     $(modalId).css('display', 'none');
}

/*-------------------------
*  モーダルウィンドウの表示位置調整
---------------------------*/
function centeringModalPosition(modalId){
     //画面幅取得
     var w = $(window).width();
     //画面高さ取得
     var h = $(window).height();

     //モーダルウィンドウの幅取得
     var cw = $(modalId).outerWidth(true);
     //モーダルウィンドウの高さ取得
     var ch = $(modalId).outerHeight(true);

     //モーダルウィンドウの横位置計算
     var pxleft = ((w - cw)/2);
     //モーダルウィンドウの縦位置計算
     var pxtop = (((h - ch)/2))/2;

     $(modalId).css({"left": pxleft + "px"});
     $(modalId).css({"top": pxtop + "px"});

}
/*-------------------------
*  対象セルの座標取得
---------------------------*/
function getCurentCell(e){
    var row = e.target.parentNode.rowIndex;
    var col = e.target.cellIndex;
    var targetCell = row + '-' + col;
    return targetCell;
}



function debugPrintIndex(e){
    //行番号取得
    var row = $(e.target).closest('tr').index();
    //列番号取得
    var col = e.target.cellIndex;

    console.log('行:列 = ' + row + ':' + col);

    var targetCell = [row, col];
    return targetCell;

}
<div id="table-edit-area">
        <table id="edit-table-hoihoi" class="table table-bordered">
                <tbody>
                        <tr>
                                <td>見出し1</td>
                                <td>見出し2</td>
                                <td>見出し3</td>
                        </tr>
                        <tr>
                                <td>1-1</td>
                                <td>1-2</td>
                                <td>1-3</td>
                        </tr>
                        <tr>
                                <td>2-1</td>
                                <td>2-2</td>
                                <td>2-3</td>
                        </tr>
                        <tr>
                                <td>3-1</td>
                                <td>3-2</td>
                                <td>3-3</td>
                        </tr>
                </tbody>
        </table>
</div>

<!-- セル内編集用ののモーダルウィンドウ -->

<div id="modal-overlay"></div>
<div id="td_editor_modal">
        <div id="edit_box"></div>

        <div id="targetCell" style="display: none;"></div><!-- ←セルの座標を格納 -->
        <div class="btn-control">
                <button id="do-save" class="btn btn-primary">保存</button>
                <button id="modal-close" class="btn btn-primary">キャンセル</button>
        </div>
</div>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/26 10:50

    解決済みのようですが。。。
    テーブルセルのonclick内で#do-saveのonclickを定義しているのが問題です。
    $('hoge').on('click',function(){hogehoge});
    上記のように定義した場合、onclickイベントが"追加"されます。
    そのため、いままで定義した全てのonclickイベントが走ってしまっていたのでしょう。

    回避方法は、
    $(‘hoge’).unbind(‘click’);
    のように、一度イベントをクリアしてあげればいいはずです。

    キャンセル

  • 2015/10/26 14:56

    ありがとうございます。onclikcイベントの入れ子が原因なのはわかっていましたが、回避方法が分かりませんでした。

    ご提示いただいたunbindを試してみたのですが、入れる場所の検討がつきませんでした。
    解決済みですので、別の質問を上げさせていただきます。

    キャンセル

0

Jqueryでクリックされたテーブルの位置(X行X列目)を取得する事ができるようですが、これで解決できますでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/25 08:14

    操作したセルのインデックスを取得して強制的に書き戻すセルを指定することを試してみましたが、編集→確定を繰り返すと、それまでに操作したセルがすべて反映してしまうようです。

    本文中に動作サンプルのURLを記載しました。コンソール上にエディタの編集内容を反映したセルの位置を「行:列 = 0:3」のように出力するようにしています。
    操作したエレメントは配列に格納されていくんでしょうか?ループで処理したように動作しています。

    キャンセル

  • 2015/10/25 14:16

    jQueryのselectorで eq()を用いてセルの特定が出来ますが、
    これで値を変えるというのは如何でしょうか?
    モーダルウインドウへは x, y の値さえ渡してしまえば、
    モーダルウインドウから selector指定は可能かと思いますので。
    (試してません・・・)

    ーーー
    <script>
    $(function(){
     $('[id=edit-table-hoihoi] > tbody > tr > td').on('click',function(){
      y = this.parentNode.rowIndex;
      x = this.cellIndex;
      selector = "table tr:eq(" + y + ") td:eq(" + x + ")"
      $(selector).text("change");
     });
    });
    </script>
    ーーー

    $('[id^=edit-table] の所ですが、 $('[id=edit-table-hoihoi] では
    ないのでしょうか? 例に上げて頂いている中に、#edit-table が
    ありませんでしたので・・・

    キャンセル

  • 2015/10/25 18:51

    ありがとうございます。

    >jQueryのselectorで eq()を用いてセルの特定が出来ますが、
    >これで値を変えるというのは如何でしょうか?

    すでに試してみたのですが、だめでした。確かに指定したセルは書き換わるのですが、それまでに操作したセルもすべて書き換わってしまいます。

    本文中の動作サンプルでお試しいただくとわかるのですが、以下のような現象が発生します。
    1.座標0-0をクリック→編集せずにキャンセル
    2.座標2-1をクリック→編集せずにキャンセル
    3.座標3-2をクリック→編集して確定
    4.3の編集内容が、座標0-0 2-1 3-2 に反映される

    キャンセルではなく都度確定した場合でも同様に、それまで操作したセルが最後に編集した内容にすべて書き換わってしまいます。

    >$('[id^=edit-table] の所ですが、 $('[id=edit-table-hoihoi] では
    >ないのでしょうか? 例に上げて頂いている中に、#edit-table が
    >ありませんでしたので・・・

    すみません。特に特記することでもないかと思って記載していませんでした。
    もともと複数のテーブルが存在しており、テーブルのIDはすべてedit-table-***というIDが振られています。
    そのため、セレクタを「edit-tableから始まる」としています。
    念のために、$('[id=edit-table-hoihoi] として動作確認してみましたが、状況は変わりませんでした。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる