Fl4m3Ph03n1x

Fl4m3Ph03n1x

Enable/disable a button in Phoenix 1.7 depending on state

Background

I have a button that may be disabled or not, depending on a set of conditions. I want to disable/enable the button without having to reload the page.

To achieve this I am using the following code:

my_app_live.ex

#provided as a sample
def disable_buttton? do
  if :rand.uniform(100) > 50 do
    "true"
  else
    "false"
  end
end

my_app.html.heex

<.button disabled={disable_button?)}>Execute Command</.button>

core_components.ex

  def button(assigns) do
    extra = assigns_to_attributes(assigns, [:disabled])

    assigns = assign(assigns, :disabled?, case Map.get(extra[:rest], :disabled) do
      "true" -> true
      _ -> false
    end)

    ~H"""
    <p><%= "INSIDE BUTTON: #{inspect(@disabled?)}" %></p>
    <button
      type={@type}
      class={if @disabled? do
      [
        "rounded-md bg-slate-400 px-3 py-2 text-sm font-semibold text-white shadow-sm",
        @class
      ]
    else
      [
        "rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm",
        "active:text-white/80",
        @class
      ]
    end}
      {@rest}
    >
      <%= render_slot(@inner_block) %>
    </button>
    """
  end

Problem

For some reason, <p><%= "INSIDE BUTTON: #{inspect(@disabled?)}" %></p> always shows true and thus the button is always disabled.

In reality disable_buttton? may return true/false depending on which buttons are selected (if all forms have a value, then the button should be enabled), however I am unaware of any pattern to do this in Phoenix.

I am also not convinced I am using assigns properly.

Questions

  1. How can I enable/disable a button in Phoenix, depending on state?
  2. Am I using assigns_to_attributes and assign correctly in this sample?

I read Phoenix.Component — Phoenix LiveView v0.19.5 but I still don’t quite understand what I am missing here.

Marked As Solved

Fl4m3Ph03n1x

Fl4m3Ph03n1x

Issues found

The main reason my code didn’t work was because my disable_button? function was returning "false" instead of false. To be more precise:

So, in Phoenix LV, if the value is false the attribute disabled is removed from the node, while if it is any other thing (like "false"), the node gets the attribute as disabled=“something else”, which means that because disabled is still present, irrespective of value, it is considered as a disabled button.

This differs from the behaviour in the browser, where if I add disable="false" the browser will not consider the node disabled.

Source: Enable/disable a button in Phoenix 1.7 depending on state - #6 by Fl4m3Ph03n1x - Questions / Help - Elixir Programming Language Forum

Another issue is that this function also needs to return a value that depends on the state itself. In this case I am generating a random number, which is independent of state, thus the button would never update.

Answer

So, for those who are curious, this is the code I ended up with:

core_components.ex

This is my modified button function:

  @doc """
  Renders a button.

  ## Examples

      <.button>Send!</.button>
      <.button phx-click="go" class="ml-2" disabled=false>Send!</.button>
  """
  attr :type, :string, default: nil
  attr :class, :string, default: nil
  attr :disabled, :boolean, default: false
  attr :rest, :global, include: ~w(form name value)

  slot :inner_block, required: true

  def button(assigns) do
    ~H"""
    <button
      type={@type}
      class={if @disabled do
      [
        "rounded-md bg-slate-400 px-3 py-2 text-sm font-semibold text-white shadow-sm",
        @class
      ]
    else
      [
        "phx-submit-loading:opacity-75 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm",
        "hover:bg-indigo-500 active:text-white/80",
        @class
      ]
    end}
      {@rest}
      disabled={@disabled}
    >
      <%= render_slot(@inner_block) %>
    </button>
    """
  end

And here is how I use it:

my_app_live.html.heex

<.button class="min-w-full" disabled={disable_button?(@param1, @state)}>Execute Command</.button>

This depends on the state, because the state changes with time, which means my button’s appearance will also change with time!

Popular Frontend topics Top

AstonJ
Inspired by @dbernheisel’s post here, which CSS framework do you use and why?
New
AstonJ
I was watching this video by Richard Feldman (Elm core team) and he’s predicting TypeScript is going to take over the JS world: ...
New
AstonJ
DHH might like you to believe they are a thing of the past: https://twitter.com/dhh/status/1275902566719610880 I actually went down thi...
New
AstonJ
If you know of any good learning resources for Svelte please post them here :smiley: Here’s some to get us started: The official tutori...
New
First poster: bot
Fable 3.1.3 has been released. Link: Release 3.1.3 · fable-compiler/Fable · GitHub
New
First poster: AstonJ
A new Svelte blog post/announcement has been posted! Get the full details here: What's new in Svelte: May 2021
New
mrmurphy
The situation Hi there! I’m working on a live view app right now that encrypts sensitive user content (text and images) using the browser...
New
jubocade
What is the best course of front end (live webinars or recorded)? So I already have basic understanding of HTML CSS JS and React but I wa...
New
AlessandroDsgroup
Hi to everyone, we are experiencing a 401 error related to the connection of the websocket (in reference to our web app); we are unable ...
New
NewsBot
React v18.3.1 has been released. Link: Release 18.3.1 (April 26, 2024) · facebook/react · GitHub
New

Other popular topics Top

AstonJ
A thread that every forum needs! Simply post a link to a track on YouTube (or SoundCloud or Vimeo amongst others!) on a separate line an...
New
malloryerik
Any thoughts on Svelte? Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue...
New
PragmaticBookshelf
A PragProg Hero’s Journey with Brian P. Hogan @bphogan Have you ever worried that your only legacy will be in the form of legacy...
New
Exadra37
I am a Linux user since 2012, more or less, and I always use Ubuntu on my computers, and my last 2 laptops have been used Thinkpads, wher...
New
Exadra37
Oh just spent so much time on this to discover now that RancherOS is in end of life but Rancher is refusing to mark the Github repo as su...
New
gagan7995
API 4 Path: /user/following/ Method: GET Description: Returns the list of all names of people whom the user follows Response [ { ...
New
PragmaticBookshelf
Author Spotlight James Stanier @jstanier James Stanier, author of Effective Remote Work , discusses how to rethink the office as we e...
New
AstonJ
Chris Seaton, the creator of TruffleRuby has died. It appears from suicide :cry: He left this note on Twitter on the weekend: And one...
New
First poster: bot
Large Language Models like ChatGPT say The Darnedest Things. The Errors They MakeWhy We Need to Document Them, and What We Have Decided ...
New
DevotionGeo
I have always used antique keyboards like Cherry MX 1800 or Cherry MX 8100 and almost always have modified the switches in some way, like...
New