Declarative assigns fail if a function component has multiple clauses

  # attr :form, Phoenix.HTML.Form, required: true
  # Above declarative assign commented out to prevent warning:
  # this clause cannot match because a previous clause always matches

  def name(%{form: _} = assigns) do
    ~H"""
    <.input
      field={@form[:name]}
      placeholder="Name"
      autocomplete="off"
      phx-debounce="2000"
      wrapper_class="flex-1 mr-4"
      class={field_class()}
      error_class={error_class()}
    />
    """
  end

  # attr :volunteer, Volunteer, required: true
  # Above declarative assign commented out to prevent error:
  # attributes must be defined before the first function clause

  def name(assigns) do
    ~H"""
    <div class="justify-self-start overflow-auto font-bold text-teal-600">
      <%= @volunteer.name %>
    </div>
    """
  end

Hi @rayex while what you are saying is true I don’t really understand your point. If the attribute is required, then the first clause will always match. That is true. It looks like you probably want two different functions.

Hi Ben,

Yes 2 distinct functions will work in allowing separate declarative assigns (attr’s) for each function.

This is what I did in the end like so:

attr :form, Phoenix.HTML.Form, required: true

attr :field_class, :list, default: @field_class

attr :error_class, :string, default: @error_class

def name(assigns) do

~H"""

<.input

field={@form[:name]}

placeholder="Name"

autocomplete="off"

phx-debounce="2000"

wrapper_class="flex-1 mr-4"

class={@field_class}

error_class={@error_class}

/>

"""

end

attr :volunteer, Volunteer, required: true

def item_name(assigns) do

~H"""

<div class="justify-self-start overflow-auto font-bold text-teal-600">

<%= @volunteer.name %>

</div>

"""

end

However initially I wanted to name both functions name/1 like so:

**def name(%{form: _} = assigns) do**

**~H”””**

**<Input Field HTML>**

**”””**

**end**

**def name(assigns) do**

**~H”””**

**<Item HTML>**

**”””**

**end**

So 2 function clauses representing 2 different components.

And it worked A1 at runtime but would not allow to specify attr’s for them.

I realize it is incongruent to use the same name for 2 distinct components.

But pattern matching is idiomatic in Elixir I thought maybe it should be allowed.

So I just thought to share this “issue” and ensure it was not an “overlook”.

Regards,

Raymond

It is allowed, the logic itself is what is flawed here. If form is required, then the first pattern will always happen because the only part of the pattern that is there is form. Your initial post by the way only indicates that you got a warning. Did you get a warning or an error?

1 Like

Both error for 1st clause and warning for 2nd or is it vice versa.

When talking about an error or warning please copy and paste the full text.

1 Like