DEV Community

Cover image for [TIL] Reusable LiveView.JS commands with JS.exec
Dung Nguyen for OnPoint Vietnam

Posted on

3

[TIL] Reusable LiveView.JS commands with JS.exec

This article was originally posted on https://bluzky.github.io/2023-07-12-til-reusable-liveview-js-commands-with-js-exec/

In this post I will build a simple dropdown for demo purpose. Not fully functional as a real dropdown :D.

1. Duplicated code

<div
  class="relative inline-block m-10"
  id="my-dropdown"
  phx-mounted={@open && (JS.show(to: "#my-dropdown .dropdown-content") |> JS.add_class("bg-blue-300", to: "#my-dropdown .dropdown-btn"))}
>
  <div
    class="dropdown-btn border border-gray-100 px-4 py-2 rounded-lg bg-gray-700 text-white inline-block cursor-pointer"
    phx-click={JS.show(to: "#my-dropdown .dropdown-content") |> JS.add_class("bg-blue-300", to: "#my-dropdown .dropdown-btn")}
  >
    Toggle button
  </div>
  <div class="dropdown-content absolute hidden bottom-0 left-0 translate-y-full w-[275px] bg-slate-50 rounded-lg border border-slate-200 shadow-md py-5">
    <div class="border-b hover:bg-slate-100 px-5 py-2">Item 1</div>
    <div class="border-b hover:bg-slate-100 px-5 py-2">Item 2</div>
    <div class="border-b hover:bg-slate-100 px-5 py-2">Item 3</div>
    <div class="border-b hover:bg-slate-100 px-5 py-2">Item 4</div>
    <div class="border-b hover:bg-slate-100 px-5 py-2">Item 5</div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

2. Writing a function

To avoid duplicated JS code, you can write a function in LiveView component

def open_dropdown(id) do
    [to: "##{id} .dropdown-content"]
    |> JS.show()
    |> JS.add_class("bg-blue-300", to: "##{id} .dropdown-btn")
end
Enter fullscreen mode Exit fullscreen mode

and update your template

<div
  class="relative inline-block m-10"
  id="my-dropdown"
  phx-mounted={@open && open_dropdown("my-dropdown")}
>
  <div
    class="dropdown-btn border border-gray-100 px-4 py-2 rounded-lg bg-gray-700 text-white inline-block cursor-pointer"
    phx-click={open_dropdown("my-dropdown")}
  >
    Toggle button
  </div>
  <div class="dropdown-content absolute hidden bottom-0 left-0 translate-y-full w-[275px] bg-slate-50 rounded-lg border border-slate-200 shadow-md py-5">
    <!-- Your dropdown content -->
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

This way you write code in 2 separated modules and you have to switch between them to understand how it works.

3. Reuse code with JS.exec

JS.exec's document says:

Executes JS commands located in element attributes.

The followed example make me think that it only support some special attributes like phx-remote and phx-* attributes. Recently I found that it could be any attribute name.

The example above can be rewrite:

<div
  class="relative inline-block m-10"
  id="my-dropdown"
  action-open-dropdown={
    JS.show(to: "#my-dropdown .dropdown-content")
    |> JS.add_class("bg-blue-300", to: "#my-dropdown .dropdown-btn")
  }
  phx-mounted={@open && JS.exec("action-open-dropdown")}
>
  <div
    class="dropdown-btn border border-gray-100 px-4 py-2 rounded-lg bg-gray-700 text-white inline-block cursor-pointer"
    phx-click={JS.exec("action-open-dropdown", to: "#my-dropdown")}
  >
    Toggle button
  </div>
  <div class="dropdown-content absolute hidden bottom-0 left-0 translate-y-full w-[275px] bg-slate-50 rounded-lg border border-slate-200 shadow-md py-5">
    <!-- Your dropdown content -->
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

This way you don't have to switch between files to get full implementation logic.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay