前回の続き。
前回はRailsの基本機能で子の入力件数に規制をかけましたが、エラー表示が更新ボタン押下時なので、タイミングが遅く、明細行追加時に制御したいという要求が出た際の解決策を考えていきます。
モデル制御時の不満点
Rails標準機能によるモデル制御の場合でも、結果的に明細件数を制御できますので、問題でも障害でも不具合でもなく「不満」という表現にいたしました。
Javascript制御では何ができるか?
エラーチェック時での制御ではなく、ボタン押下時での判断ができる
前回の記事のデメリットでも書きましたが、Javascriptでは、きめ細かい制御が可能です。
Javascriptでの解決方法
Javascriptでの解決方法その1:明細追加ボタン押下時にアラートを出すことは可能か?
以前の記事、
より、JQueryのロジックを抜粋してみます。
$('#tasks').on('cocoon:before-insert', function() { console.log("cocoon:before-insert!"); }) .on('cocoon:after-insert', function() { console.log("cocoon:after-insert!"); }) .on('cocoon:before-remove', function() { console.log("cocoon:before-remove!"); }) .on('cocoon:after-remove', function() { console.log("cocoon:after-remove!"); });
上記のcocoon:before-insert
で超過しそうなときにalert()
を出すことができれば良いのですが、cocoon:before-insert
は単なる前の処理なので、alert()
を出したとしても、行は追加されます。
ですので、他のアイディア(githubにある、ボタン側の表示抑制)を考えてみます。
Javascriptでの解決方法その2:明細追加ボタン押下時にボタン自身を消す
cocoon:after-insert
で行のMAX値(例えば5件)に達した場合、明細追加ボタンを非表示にすることはできそうです。
その場合、cocoon:after-remove
で5件を割った場合、明細追加ボタンを復活させます。
$('#tasks').on('cocoon:before-insert', function() { }) .on('cocoon:after-insert', function() { let cnt = 子件数カウント処理 if (cnt >= 5) { document.querySelector('ボタン周りのidまたはclass').style.display = 'none'; } }) .on('cocoon:before-remove', function() { }) .on('cocoon:after-remove', function() { let cnt = 子件数カウント処理 if (cnt <= 5) { document.querySelector('ボタン周りのidまたはclass').style.display = 'block'; } });
OAOO的には「子件数カウント処理」が共通化できそうですので、function化しましょう。
子件数カウントfunctionを実装する
そのまま件数をカウントすると、削除済み件数も加算してしまう
前回までに使用した例題をサーバーから実行し、F12を押下し「#codedetails .nested-fields」で検索すると、件数がわかります。
let cnt = document.querySelectorAll('#codedetails .nested-fields').length;
しかし、件数が予想よりも多いことがわかります。
削除ボタンで削除した行もカウントされています。
削除した子が残るケースは、あくまでもこの画面で削除した場合です。
更新の都度、削除した子は消えてなくなります。
削除済を除いてカウントしていく
JQueryなどを利用すればもっと簡単に件数がカウントできるのかもしれませんが、Javascriptでカウントしていきます。
let obj = document.querySelectorAll('#codedetails .nested-fields'); let cnt = 0; obj.forEach(function(field, idx) { if (field.style.display !== 'none') { cnt++; } }) return cnt;
querySelectorAll()
で一発で取得できる方法もあるのかもしれませんが、あまり凝らないで求める方法はこんな感じでしょうか。
あとはfunction化して、cntをreturnすればよいかと思います。
次回
次回は、行コピーを考えたいと思います。