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

dyowee
Why or when should one choose Tailwind over Bootstrap? :slight_smile:
New
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
Fl4m3Ph03n1x
Background I have created a fresh Phoenix app using mix phx.new.web web_interface --no-dashboard --no-ecto --no-gettext --no-mailer insid...
New
Fl4m3Ph03n1x
Background I have a Phoenix application, where all pages (expect the login page) have a menu at the top. This menu will therefore only a...
New
sona11
I’m currently working on a JavaScript project that involves converting user-supplied text to numbers. Dealing with different areas and th...
/js
New
gameengineer
We are developing on Samsung Tab Active 4 Pro using Android Studio, kotlin and java. We are getting what we think are app deadlocks. The ...
New
avipal
I have an application where it is three layer 1st layer- A legacy core routines 2nd layer- built on top of the Core routine using Dotno...
New
hosseinkhosromanesh
hello , i should code a cluster like image bellow we have no challenge in coding backend but in front need some clue to do this its a dy...
/js
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

Other popular topics Top

wolf4earth
@AstonJ prompted me to open this topic after I mentioned in the lockdown thread how I started to do a lot more for my fitness. https://f...
New
Exadra37
On modern versions of macOS, you simply can’t power on your computer, launch a text editor or eBook reader, and write or read, without a ...
New
Rainer
Not sure if following fits exactly this thread, or if we should have a hobby thread… For many years I’m designing and building model air...
New
PragmaticBookshelf
Learn different ways of writing concurrent code in Elixir and increase your application's performance, without sacrificing scalability or...
New
DevotionGeo
The V Programming Language Simple language for building maintainable programs V is already mentioned couple of times in the forum, but I...
New
AstonJ
Biggest jackpot ever apparently! :upside_down_face: I don’t (usually) gamble/play the lottery, but working on a program to predict the...
New
foxtrottwist
A few weeks ago I started using Warp a terminal written in rust. Though in it’s current state of development there are a few caveats (tab...
New
New
PragmaticBookshelf
Author Spotlight: Sophie DeBenedetto @SophieDeBenedetto The days of the traditional request-response web application are long gone, b...
New
New