shahryarjb

shahryarjb

Adding Phoenix.LiveView.JS function for getting `getBoundingClientRect` params

When proposing or suggesting something please consider:

As my experience implementing getBoundingClientRect as Phoenix.LiveView.JS function and returns all the parameters of this JS function I mean (height, top, left and etc size) can be help full for complex client side component.

It keeps the ecosystem more clear and integrated. It can prevent the use of other client frameworks or js hook.


For example we have an accordion that is created with Phoenix component and Phoenix.LiveView.JS:

Show or open the accordion:

  def show_accordion_content(js \\ %JS{}, id) when is_binary(id) do
    js
    |> JS.show(to: "##{id}")
    |> JS.show(
      to: "##{id}-content",
      time: 500,
      transition:
        {
           "transition-all transform ease-out duration-300", 
           "will-change-[opacity] opacity-0 h-0",
           "will-change-auto opacity-100 h-[400px]"
        }
    )
  end

As you see I use hard coded height h-[400px] because browsers do not accept transition for h-auto, we have all the commands to open an accordion in Phoenix liveView as you see except some information about the element. It forces me to use hook or something like AlpineJS.

It can be an option for JS.show, JS.hide and (before or after doing operation) etc.

Thank you in advance


Refs:

Most Liked

steffend

steffend

Phoenix Core Team

@garrison already made some very good points. We don’t plan to make complex JS commands.

There are lots of improvements planned for hooks. One of them is to actually expose sticky JS commands like this:

mounted() {
  const js = this.js();
  // js.show, js.hide, js.transition, etc.
  js.toggleClass(this.el, ...);
}

Another big improvement will be colocated hooks that will allow defining the necessary JavaScript next to the components themselves.

garrison

garrison

I did not elaborate because the grid trick in question was linked above :slight_smile: Here is a StackOverflow question with more details:

Honestly you probably could find a way to do it with radio buttons and pure CSS, but I wouldn’t. What I meant was that the animation can all be done with CSS (no JS.transition needed), and then all you need is JS.toggle_class to trigger the CSS animations.

First, you wrap each item in a grid container, and then you use CSS to toggle grid-template-rows between 0fr and 1fr. You set overflow: hidden on the child (the accordion content in your case) so that it’s not visible when closed.

The CSS would look like this:

.container {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 100ms;
}
.container.open {
  grid-template-rows: 1fr;
}

.content {
  overflow: hidden;
}

The HEEx would look like this:

<div>
  <div class="container" phx-click={@open}>
    <div class="content">Foo</div>
  </div>
  <div class="container" phx-click={@open}>
    <div class="content">Bar</div>
  </div>
</div>

And then, if you want all of the other items to close when you open one, you would do this (otherwise you could just use JS.toggle_class("open")):

open =
  JS.remove_class("open", to: ".container.open")
  |> JS.add_class("open")

This is just a minimal demonstration of the mechanism, obviously you would also need some sort of title for each item to actually click on :slight_smile:

garrison

garrison

The code I’ve written to get around this issue (using the liveSocket to trigger JS commands in data- attributes) is some of my least favorite in my app - it’s obviously suboptimal. I think opening up the sticky API is inevitable, and I don’t see any obvious problems (it’s the same thing we’re already doing anyway, just directly). I would imagine the work simply hasn’t been done yet - JS commands are still relatively new and improving quickly. We only just got toggle_class, which was a big improvement :slight_smile:

Last Post!

sezaru

sezaru

I meant the sticky opts one, thanks for the link

Where Next?

Popular in Proposals: Ideas Top

bamorim
Story behind Recently, I gave a talk on a meetup about improving performance of Phoenix applications and the example app was a LiveView ...
New
dimitarvp
To @jonatanklosko and @the-mikedavis: I see that there is a Rust crate at crates.io: Rust Package Registry but it is pointing at https:/...
New
shahryarjb
When proposing or suggesting something please consider: As my experience implementing getBoundingClientRect as Phoenix.LiveView.JS funct...
New
Astolfo
When generating a release with phx.gen.release --docker a debian version is used by default to avoid “DNS issues” on Alpine. It seems li...
New
Redbaritone
In the current Auth code, the email must change to be valid. This may be true for the two situations the author has in mind: Registering ...
New
GenericJam
I’ve been messing around with image generation models recently and thought this could be wrapped in a library or people could just use th...
New
eagle-head
Hi everyone, I’ve been researching Content Security Policy Level 3 support in Phoenix and wanted to share my findings and a proposal for...
New

Other popular topics Top

jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49084 226
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42533 114
New

We're in Beta

About us Mission Statement