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!

Where Next?

Popular Frontend topics Top

The_Exile
I am new to programming. I started reading Eloquent Javascript 3rd Edition, as the book comes highly recommended as a good place for beg...
/js
New
brian
I’m working with a designer who created a design in Photoshop. I am mostly a Node.js and Android dev, but when I have worked with designe...
New
axelson
In Elixir I love to use the library GitHub - sasa1977/boundary: Manage and restrain cross-module dependencies in Elixir projects to enfor...
New
beberardinelli
Hi! I just started coding a few months ago and I am trying to get all the help I can get. My friend showed me this debugging tool called...
New
sona11
What is the difference between tuple relational calculus (TRC) and domain relational calculus (DRC)? What distinguishes them from relatio...
New
PickyBiker
I have done small amounts of programming for IOS and for Android, but now I need to create something that works with both. What are the ...
New
ramiro-marinio
Hello. So unexperienced frontend dev here. Basically, 3 or 4 months ago I started working on a project and I committed the capital sin of...
New
wilsoc31
First time building an app. It will run for Android and also for iPhone 15 but will not for iPod. Not sure why or where to even begin. ...
New
Arpeggio
I have the following HTML structure, which is dynamically rendered from a Sightly (HTL) page in a new AEM component we’re building, so I ...
New
ounce591
I am currently designing the navbar of a workout tracking app written using React Native. The navbar has three buttons: Splits/Plans ...
New

Other popular topics Top

PragmaticBookshelf
Write Elixir tests that you can be proud of. Dive into Elixir’s test philosophy and gain mastery over the terminology and concepts that u...
New
AstonJ
Or looking forward to? :nerd_face:
503 15149 280
New
DevotionGeo
I know that -t flag is used along with -i flag for getting an interactive shell. But I cannot digest what the man page for docker run com...
New
AstonJ
There’s a whole world of custom keycaps out there that I didn’t know existed! Check out all of our Keycaps threads here: https://forum....
New
PragmaticBookshelf
Rust is an exciting new programming language combining the power of C with memory safety, fearless concurrency, and productivity boosters...
New
AstonJ
Do the test and post your score :nerd_face: :keyboard: If possible, please add info such as the keyboard you’re using, the layout (Qw...
New
PragmaticBookshelf
An illustrated guide to understanding and effectively using regular expressions. Staffan Nöteberg To effectively use regular expressi...
New
AstonJ
This is cool! DEEPSEEK-V3 ON M4 MAC: BLAZING FAST INFERENCE ON APPLE SILICON We just witnessed something incredible: the largest open-s...
New
PragmaticBookshelf
A concise guide to MySQL 9 database administration, covering fundamental concepts, techniques, and best practices. Neil Smyth MySQL...
New
mindriot
Ok, well here are some thoughts and opinions on some of the ergonomic keyboards I have, I guess like mini review of each that I use enoug...
New