DestroyedSoul

DestroyedSoul

Custom components behave differently from core components

Hello,

In my project I need custom core components, i.e. input fields etc that are styled a bit differently. I know I can provide class for the core input component, but then it only affects the text field itself not its label.

What I tried to do is to create my own Inputs.default_input, that would behave the same way as core input, but with custom tailwind classes. I literally copied the code form the core components and adjust the looks. Everything works, except for one thing:

Let’s take email as an example. When I start typing the email, the error is displayed that it has to have @ sign. This works for both my and core components.
However, when I add the @ sign and email becomes valid, the error should disappear. Works for core component, but not for my component.

My component is added like this:

<Inputs.default_input
      field={@form[:email]}
      type="email"
      label="Email"
      placeholder="Enter email address"
 />

The implementation mirrors the core component:

... attributes ...
def default_input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
    errors = if Phoenix.Component.used_input?(field), do: field.errors, else: []

    assigns
    |> assign(field: nil, id: assigns.id || field.id)
    |> assign(:errors, Enum.map(errors, &translate_error(&1)))
    |> assign_new(:name, fn -> if assigns.multiple, do: field.name <> "[]", else: field.name end)
    |> assign_new(:value, fn -> field.value end)
    |> default_input()
end

... non text default_inputs()...

def default_input(assigns) do
    ~H"""
    <div class="fieldset mb-2">
      <label>
        <span :if={@label} class="text-base text-base-content font-normal">{@label}</span>
        <input
          type={@type}
          name={@name}
          id={@id}
          value={Phoenix.HTML.Form.normalize_value(@type, @value)}
          class={[
            @class || "mt-1 w-full input text-base text-base-content",
            @errors != [] && (@error_class || "input-error text-base")
          ]}
          {@rest}
        />
      </label>
      <.error :for={msg <- @errors}>{msg}</.error>
    </div>
    """
  end

The only difference is tailwind classes in the default_input().
If I keep the code literally as-is, it still doesn’t work.

def default_input(assigns) do

    ~H"""

    <div class="fieldset mb-2">
        <label>
           <span :if={@label} class="label mb-1">{@label}</span>
           <input
             type={@type}
             name={@name}
             id={@id}
             value={Phoenix.HTML.Form.normalize_value(@type, @value)}
             class={[
               @class || "w-full input",
               @errors != [] && (@error_class || "input-error")
             ]}
            {@rest}
          />
       </label>
       <.error :for={msg <- @errors}>{msg}</.error>
   </div>
"""
end

But it starts to work when I do this:

def default_input(assigns) do
 ~H"""
     <.input {assigns} />
 """
end

Is there anything special about the core components that I am missing?

Marked As Solved

DestroyedSoul

DestroyedSoul

While I was trying to reproduce this issue in the new repo, I found the problem.
My Inputs module was defined like this:

defmodule MyApp.Components.Inputs do
  use Phoenix.Component
  use MyApp, :html
 
...
end

:html is there to get access to translate_error(). However, I import all my custom components (indirectly) in html_helpers(). Apparently, it made a conflict even though compiler did not complain (because I import Components module, that, in its turn, has a __using__ macro that makes available other components).

I changed into:

defmodule NutrihiveWeb.Components.Inputs do
  use Phoenix.Component
  import MyApp.CoreComponents
...
end

and now the problem seems to have gone.

Where Next?

Popular in Questions Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 44265 214
New

We're in Beta

About us Mission Statement