前回の続き。
今回は、失敗をもとに、ビューで細工するのをやめ、JQueryでコードを実装していきます。
HTMLの中身を調査し、仕様を決める
INPUTタグののidを覗いてみる
INPUTタグを覗いてみたところ、name属性には[]が入っており、取り扱うには厳しい気がします。
idはキャメルケースのようですので、こちらを活用したほうが良さそうです。
idを見てみると、ビューで描画された行は0から始まりますが、行追加ボタンで追加された行は、13桁程度の数字がセットされていますね。
なので、配列等にセットする際、添字としては使用できないでしょうね。
どの行からコピーするか?
cocoonが決めたJQueryのエントリーポイントに実装することになるのですが、ビューのみの場合と比較して、多少の自由度は増します。
今回は、行追加リンクを押下する直前時点での最終行の値を、新たに追加する行にコピーするようにします。
別ボタンを用意するか?
行追加ボタンの他に、行コピー(追加&複写)といったボタンを別途用意した場合、JQueryのロジックを2つ用意する必要がありそうですね。ちょっと冗長だと思います。
ですので、ボタンの横に「□行コピー」といったチェックボックスを用意し、チェックされたらコピーの処理を追加します。
コピーロジックを実装する
明細行計算のロジックを改良する
で、紹介した行計算ロジックを改良あるいはコピーします。
(どちらでも構いません。)
一例をあげます。
cocoon:after-insert
にペーストするか、適当なファンクションにして、cocoon:after-insert
から呼び出します。
let obj = document.querySelectorAll('#codedetails .nested-fields'); let flds_id = []; // 多次元配列用 obj.forEach(function(field, idx) { if (field.style.display !== 'none') { let work_id = []; let input_obj = field.querySelectorAll("input"); input_obj.forEach(function(field2, idx2) { if (field2.id.indexOf('_destroy') == -1) { work_id.push(field2.id); } }) flds_id.push(work_id); } }) return flds_id;
flds_id
は2次元配列(行、列)になります。
(Rubyと同様)Javascriptは初っ端で2次元配列を定義できないので、work_id
を別途用意し、列の配列をflds_id
にプッシュしています(flds_id[idx]
に直接プッシュしていっても構いません)。
行削除ボタン自体もINPUTタグですので、_destroyが含まれるINPUTは除外します。
上記例はINPUTですが、INPUTの中でもvalueで値がコピーできないものもあります。そういった項目が行に含まれる場合は、type属性で除外することになります。
また、TEXTAREAやSELECTタグもvalueで行けそうですので、こちらに含めてもいいかもしれません。
要は、valueで複写できる、できないで、配列を別にし、それぞれのコピーロジックを作成を別途作成していきます。
コピーしたくない項目があった場合
例えば、ユニークキーとなるような項目をコピーした場合、重複チェックで引っかかるので、そこは空欄にしたい…のであれば、
if (field2.id.indexOf('_destroy') == -1) {
の箇所を工夫すれば良いと思います。
コピーロジックを実装する
次にコピーロジックを実装するのですが、先程の配列ごと(valueで複写できるもの、できないもの)にロジックを作っていきます。
その前に、配列の何番目から、どこにコピーするかを整理します。
もうすでにコピー先の行は作成されているので…
- コピー元の添字:配列の長さ − 2
- コピー先の添字:配列の長さ − 1
となるはずです。
以下はコピーロジック例です。cocoon:after-insert
に挿入するか、適当なファンクションにして、cocoon:after-insert
から呼び出します。
(前提条件:INPUTタグ等でvalueコピーが可能なもの、かつ、行コピーにチェックが入っていて、行が2行以上存在していること。)
let copy_moto = flds_id.length - 2; let copy_saki = flds_id.length - 1; // 各行のinputタグ(削除するボタンを除く)でループ for (let idx=0; idx<flds_id[0].length; idx++) { document.getElementById(flds_id[copy_saki][idx]).value = document.getElementById(flds_id[copy_moto][idx]).value; }
こちらで、最終行(実行段階では1行前の行)からのコピーが可能になります。
次回
次回は、最終行ではなく、任意の行をコピーしたい場合を考えてみます。