前回の続き。
- 前回のおさらい
- Stimulusのconnect()内にcocoonのロジックを移動
- Stimulusのメリットを再認識する
- 参考:共通箇所を別のファイルへ移動する
- 参考:JQueryではなく、Vanillaな書式に変更したい場合
- 次回
前回のおさらい
一見して解決したように見えるが、取ってつけた感が強い
前回の手法は、すでにcocoonを導入し、Rails7へアップグレードしたのであれば、当座の障害解決として、これでゴールなのかもしれません。
ただ、作法的に、これで良いのか? ちょっとしっくりこない気分はあります。
Stimulusのconnect()内にcocoonのロジックを移動
Stimulusだと、どんな状況でも発火するのであれば、cocoonのロジックをまるごと移動させればいいのでは?
この考え方で上手く動作するのか?確認してみましょう。
各ファイルを変更・追加する
app/javascript/controllers/index.js
を書き換えます。
// app/javascript/controllers/index.js //import CcReloadController from "controllers/ccreload_controller" //application.register("ccreload", CcReloadController) import TaskFormController from "controllers/task_form_controller" application.register("task_form", TaskFormController)
前回のCcReloadController
の2行はコメントにし、TaskFormController
の2行を追加します。
次に、app/views/tasks/_form.html.haml
をtask_form
に変更します。
.div{data: {controller: "task_form"}}
さらに、app/javascript/controllers/task_form_controller.js
を変更します。
import { Controller } from "@hotwired/stimulus" //import jquery from "jquery" //import * as common from './共通部品のJSファイル.js' export default class extends Controller { connect() { // 共通変数の定義など // stimulusにはonloadの概念がなさそう //$(window).on("page:load", function(){ // こちらにonload処理を記述 //}); $('子供のID').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!"); }); } // connect() } // export default class extends Controller
実行前に、いくつか解説します。
JQueryはimportしなくても大丈夫はなずです。
//import * as common from './共通部品のJSファイル.js'
については、あとで解説します。
$(window).on(〜
については、connect()
時点ですでにロードされていると思いますので、不要です。
●app/javascript/application.js
// app/javascript/application.js $(document).on('ready page:load turbolinks:load turbo:load', function() { (以下略)
にあったready page:load turbolinks:load turbo:load
的な行も不要になります。
app/javascript/application.jsのロジックは除去する
テストの邪魔になりますので、前々回に追加したapp/javascript/application.js
のcocoonのロジックは除去しておきましょう。
動作確認
サーバーを起動し、行追加・削除のボタンを押下し、ブラウザのコンソールに文言が表示されたら、動作確認は完了です!
Stimulusのメリットを再認識する
Stimulusを利用すると、自然と、ビュー単位でJavascriptのファイルを分割できるようになります。
ファイルの分割で悩んでいた方には福音かもしれません。
参考:共通箇所を別のファイルへ移動する
ファイルがビュー毎に分割してしまうと、共通的なfunctionがダブってしまうという副作用が生じると思います。
放っておくと、保守が大変そうですね。
こちらは、cocoonの機能でも、Stimulusの機能でもなく、VanillaなJavascriptの仕様ですが、export/importを使って、共通functionを別ファイルへ移動しましょう。
実装例
以下は、app/javascript/controllers/task_form_controller.js
での実装例です。
import { Controller } from "@hotwired/stimulus" //import jquery from "jquery" import * as cmn from './common.js' export default class extends Controller { connect() { // 共通変数の定義など // stimulusにはonloadの概念がなさそう //$(window).on("page:load", function(){ // こちらにonload処理を記述 const foo = cmn.hoge(); //}); $('子供のID').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!"); }); } // connect() } // export default class extends Controller
●app/javascript/controllers/common.js
export function hoge() { // 処理 return 'abc'; } // function
上記例ではcommon.js
をimportし、common.js
の中にあるhoge()
を実行しています。
これでかなりスッキリすると思います。
参考:JQueryではなく、Vanillaな書式に変更したい場合
JQueryはちょっとなあ…という方へ、参考までにVanillaなJavascript表記もアップしておきます。
●app/javascript/controllers/task_form_controller.js
import { Controller } from "@hotwired/stimulus" //import * as cmn from './common.js' export default class extends Controller { connect() { // 共通変数の定義など // stimulusにはonloadの概念がなさそう // こちらにonload処理を記述 let id_obj = document.querySelector('#tasks'); // どちらか let id_obj = document.getElementById('tasks'); // お好みで // 追加処理前 id_obj.addEventListener("cocoon:before-insert",function () { console.log("cocoon:before-insert!"); }); // cocoon:before-insert // 追加処理後 id_obj.addEventListener("cocoon:after-insert",function () { console.log("cocoon:after-insert!"); }); // cocoon:after-insert // 削除処理前 id_obj.addEventListener("cocoon:before-remove",function () { console.log("cocoon:before-remove!"); }); // cocoon:before-remove // 削除処理後 id_obj.addEventListener("cocoon:after-remove",function () { console.log("cocoon:after-remove!"); }); // cocoon:after-remove } // connect() } // export default class extends Controller
結果、ちゃんと動きました。
いくつかのブログを見ると、「addEventListenerではなく、data-action
というdatasetで定義して…」と書いてあったりして、できないのかな?と思いましたが、connect()
にaddEventListenerは書けますね。
cocoonはおおもとの部分はJQueryをインストールしないとダメなのかもしれませんが、ユーザー定義の箇所についてはVanilla表記は可能なようです。
ただ、JQueryのようにメソッドチェーンで記述したら怒られました。
できないんですかね?
次回
次回は、cocoonを導入した際につまずきやすい箇所について、解決方法を考えていきます。