Open1

Phoenix(LiveView)でAlpinejsを試してみたときの記録

tatotato

これは2021年3月ごろのスクラップの整理です。
情報が古くなっているかもしれません。

導入

--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -28,13 +28,15 @@ import topbar from "../vendor/topbar"
 import Alpine from "alpinejs"
 import Hooks from "./hooks"

+Alpine.start()
+
 let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
 let liveSocket = new LiveSocket("/live", Socket, {
   params: { _csrf_token: csrfToken },
   hooks: Hooks,
   dom: {
-    onBeforeElUpdated(from, to) {
-      if (from.__x) { Alpine.clone(from.__x, to) }
+    onBeforeElUpdated(from, to){
+      if(from._x_dataStack){ Alpine.clone(from, to) }
     }
   }
 })

どういうところで使うか

  • サーバ側とのやり取りがない純粋なクライアント側でのUI操作
  • テキストエリアのautoresize等はAlpine.jsに任せればよい典型
  • phx-click後に別のアイテムにフォーカス(focus)したいときにphx-hookpush_eventではできない(かった)が、x-on:clickphx-clickと同じ要素に設定して行う(とできた)
  • 「作成」「続けて作成」といったサブミットボタンが2つあるようなフォームにおいて、押したボタンに沿って処理を行いたいときなど、phx-submit="submit"が送られる前にx-on:click=でhiddenなアイテムに値をセットする
form phx-submit="submit" x-data="{context: null}"
  input type="hidden" name="context" x-model="context"
  div x-on:click="context = 'a'; $nextTick(() => $refs.submit.click())"
    | submitA
  div x-on:click="context = 'b'; $nextTick(() => $refs.submit.click())"
    | submitB
  button x-ref="submit"

LiveViewとのデータ更新の兼ね合い

  • 基本的にLiveViewで更新も行うようなリソースでは、複雑になるので使わない方がいい
  • x-data="{}" のなかで assignされた値を使っている場合、いずれかの値が変わったタイミングにおいて、再度初期化される
  • 例えば、テキストエリアをsubmitごとに初期化したいなら form x-data="{ text: '', _timestamp: '<%= @timestamp %>' }" のような小細工がいる
  • これはsubmit時に初期化するようなイベントを発行するか、changeset由来のformにできる(推奨かな?)のであれば、changesetでするのが適切
  • Alpine.js側(x-on:click等)からHook側の処理を動かす場合は、独自イベントをHook側で作っておいて、それをdispatchする
  • Alpinejsの表現力、例えばx-on:click.awayを生かす場合は、x-on:clickで別のphx-clickイベントが定義されたタグに対してclick()イベントを送るなどもあり。
    • 例えば、モーダルで"表示領域以外をクリックされたときに閉じる"を実現する際に、イベント検知自体をAlpinejsを有効活用(.away)して、他のタグに設定されているphxなイベントを起こす等
  • LiveComponentのidを付ける大枠のタグでは、x-data=しないこと
  • x-on:click="" 等が定義されている箇所をサーバ側で出し入れ(<%= if ~ %>)すると、非表示=>表示時に発火してくれないときがあるので、x-show="" で制御する方がよさそう

その他

  • x-data に渡す内容に改行\nが入っていてエラーになるなら javascript_escape すると良さそう
    • x-data: { content: '<%= javascript_escape(content) %>' }
  • phx-submitx-on:click=$el.submit() では発火しない
    • x-on:click=$refs.submit.click() 等でclick()する