adrianbarbic

adrianbarbic

Just playing around with Phoenix.LiveView.JS and wondering if there is a way to toggle classes on and off on an element? There is ‘add_class’ and ‘remove_class’ but ‘toggle’ looks like it is just used for showing and hiding. But maybe there is a way but just can’t see it.

Showing Posts 1 to 10

Dabsy

Dabsy

I came here to ask this just now trying to make an indicator transform 180 degrees and not disappear.

https://github.com/phoenixframework/phoenix_live_view/pull/1721

It looks like its not in master yet.

I’m using dispatch for now:

js = JS.dispatch(js, "icon:rotate-180", to: "#accordion")

window.addEventListener("icon:rotate-180", e => {
    e.target.classList.toggle("transform-rotate-180")
});
Dabsy

Dabsy

I have an updated solution that supports more complexity inspired by some code I found in LiveBeats



# app.js
const execJS = (selector, attr) => {
  # this executes rendered JS commands on an element
  document.querySelectorAll(selector).forEach(el => liveSocket.execJS(el, el.getAttribute(attr)))
}

window.addEventListener('phx:collapse', e => {
  const id = `#${e.target.id}`

  if (e.target.getAttribute('data-open') === 'true') {
    execJS(id, 'js-hide')
  } else {
    execJS(id, 'js-show')
  }
})
~H"""
<div
  id="my-accordian"
  data-open="false"
  phx-click={JS.dispatch("phx:collapse", to: "#my-accordian")}
  js-show={show()}
  js-hide={hide()}
>
...
</div>
"""
overcomeoj

overcomeoj

Is there a reason to not merge the PR? Seems like a really popular request and also something built in to JS/DOM with classList.toggle? Maybe it adds too much complexity? Is the PR bad?

Dabsy

Dabsy

Not sure, I just again came in search of this functionality again two days back so I checked the PR to see why it hadn’t gone forward – just appears abandoned.

The updated solution from begleynk worked like a charm for me though.

Crossposting suggested solution for future searchers:

def toggle_expanded(js \\ %JS{}) do
  js
  |> JS.remove_class(
    "expanded",
    to: "#outer-menu.expanded"
  )
  |> JS.add_class(
    "expanded",
    to: "#outer-menu:not(.expanded)"
  )
end

It adds the class if it does not exist on the element and removes it if it does.

trisolaran

trisolaran

More like forgotten by the LV core team I would say. AFAICS they didn’t provide any feedback apart from “we’re aware of this one, just wait”. A useful feature indeed that should be part of the core JS module IMO.

how does it work though? Superficially, it looks like it first removes the class and then adds it, so shouldn’t it always end up adding it? Aren’t the remove_class and add_class commands executed in order?

JohnnyCurran

JohnnyCurran

Technically, yes, but the psuedo class :not selector in the command:

Only adds the class to the #outer-menu element if it does not have .expanded in its class list

Sebb

Sebb

never used LV.JS, so most likely stupid question: why not just use LV to toggle the class?

JohnnyCurran

JohnnyCurran

If you’re asking why not use the LV server state to render the element with / without a certain class, it’s because there are some UI interactions that don’t require a round-trip to the server which (can) introduce a couple hundred ms delay. Things like user profile menus opening/closing should be instantaneous (from a UX perspective) and don’t require the LV to keep track of its open/closed state

I hope that helps and answers your question

soup

soup

I think it implies a kind of “DOM transaction”, probably the changes are applied to a shadow DOM, while the selectors are run against the document DOM? This lets you batch changes up and do tricks like as listed but might also catch you out if you don’t expect it.

See this fiddle, where clicking remove then add (what it “looks” like the LV.JS is doing) is effectively a no-op, which isn’t observed in LV.

trisolaran

trisolaran

That doesn’t explain why it works. The first operation removes the class if the element has it, the second one adds it if the element doesn’t have it. But after the first operation the element is guaranteed not to have the class, so the second operation should always be triggered, resulting in a no-op as @soup has pointed out.

My guess is that the magic is happening here, but I wasn’t able to figure out how exactly.

Where Next? Top

Trending in Questions Top

Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
matt-savvy
Anyone here using Honeybadger? My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of Bandit.HTTPError...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews