owenfi

owenfi

To begin: I’m fairly new at web-frontend and trying to learn by cloning a popular word puzzle game.

I have an input field where a guess can be entered, in a manually crafted form in a liveview. It’s possible to enter text via real-keyboard or an onscreen rendered keyboard.

At first I was using <.input... but was having trouble styling it (not respecting class, is this expected?) so I changed to just a raw <input... so the form code is basically:

<.form id="game-guess" for={@form} phx-change="validate" phx-submit="save">
  <input type="text" id="guess-id" class="guess-box" value={@guess} field="guess" name="guess" />
  <button type="reset" class="delete-button">X</button>
</.form>

I’m attempting to convert all guesses to uppercase only, and limit to 5 characters, so my validate looks like:

def handle_event("validate", payload, socket) do
  newguess = String.upcase(payload["guess"])
  |> String.slice(0, 5)

  socket =
    assign(socket,
      guess: newguess,
      form: to_form(%{
        "guess" => newguess
      })
    )
  {:noreply, socket}
end

newguess looks correct when I inspect it, but the form doesn’t respect that / validate doesn’t work at all. I’m certain I shouldn’t be using the value={@guess} directly in the assigns (which is easy enough to remove by using value={"#{@form.params["guess"]}"} but that feels like basically the same hack) and that I am doing something wrong in the form creation, but haven’t been able to figure out what I should do. For a while I thought it was an issue with web browsers respecting capitalization changes, but the truncation also doesn’t work.

If I manually set the assigns.guess from my onscreen keyboard, then the reset button doesn’t work. I suspect they’re related.

I think my main question is: How do I update a form’s input field value in a validate so it is reflected in the view immediately?

Showing Posts 1 to 5

Hermanverschooten

Hermanverschooten

You don’t need the interpolation, value={@form.params["guess"]} will do just fine, maybe value={@form["guess"].value} is more idiomatic, Phoenix.HTML.FormField — Phoenix.HTML v3.3.0

garrison

garrison

The value is not being overwritten because LiveView does not overwrite the contents of inputs that have focus. See the docs here:

If it worked that way, you would run into all sorts of wonky behavior due to latency, because the server’s state would always be behind the client, so every time an update came back it would delete some of your text as you type.

For this sort of thing (modifying input as a user types), you can use a JS hook and some standard JavaScript to listen to the input event and uppercase the string synchronously on the client. You can find the docs for hooks here:

Then if for some reason you need to validate that the field is uppercase on the server, you can just check it on submit and throw an error (since only a malicious user would send a lowercase string to the server).

garrison

garrison

Oh, and also, the reason you can’t style the input component is because it comes pre-styled with tailwind classes and so it doesn’t pass the @class attribute in by default. But these components are literally generated into your project (they’re in core_components.ex), so you can change them to whatever you want.

What you did (styling a one-off input) is also fine - it just depends on what you’re doing. If you want to re-use that input elsewhere in the project you can turn it into another component.

owenfi

owenfi OP

Thanks for all the answers everyone! I updated to not use interpolation and it does look cleaner, but no behavior change.

The explanation about not modifying fields with focus makes complete sense, thank you for all the docs pointers! (Will try the JS Hook approach soon)

Also the styling being baked into core components is nice, too. I figured these were functions defined somewhere but thought it was at the framework level and they weren’t opening in my editor automagically so I stopped hunting for them after a bit. (Though I had read that “daunting” file a bit in the past, just forgot about it.) Would it be a bad practice to customize this version to allow passing in class definitions to append?

Finally, for the reset button: Is it possible to wire things up in a way that the default <button type="reset"... works for manually entered values? Or should I just hook that to another action and handle it directly (this seems simple and correct enough).

garrison

garrison

It’s fine - it depends on context. Obviously the more customization you add the harder the component will be to re-use. Especially with Tailwind, since you have to pass in the universe in order to style a component. You can also accept variables as assigns and then use them to dynamically choose the relevant classes (e.g. for color or size). I use that pattern a lot (though I don’t use Tailwind).

Buttons with type="reset" are pretty rare and generally not recommended, for various reasons. I think in this case the problem is that Phoenix is injecting the current value of the input into the value="..." attr, which is used to reset the input (so it just gets reset to the server value). You would have the same problem, I think, with a React controlled input.

Implementing the reset functionality in code should fix that. It should work server-side because clicking the button will steal focus from the input allowing it to be reset.

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews