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

vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
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
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
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

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
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
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31586 112
New

We're in Beta

About us Mission Statement