When a user types in some text input field, I perform a DB update (after some debouncing time).
If the DB operation fails for any reason, I should update/reset that text field with the last valid text.
In order to be able to revert the text in case of DB error, I manage the text input’s state by an assigns variable :input_foo_body
:
That’s why I created a separate state for the input field, in this example input_foo_body
:
<%= f = form_for @changeset, "#", [phx_change: :do_foo] %>
<%= textarea f, :body, [value: @input_foo_body, phx_debounce: "400"] %>
</form>
If the DB update failed, I can now re-assign :input_foo_body
to foo’s body value from the socket (the last value that was successfully inserted into DB):
def handle_event("do_foo", %{"foo" => foo}, socket) do
# some code...
case Foos.insert_or_update_foo(tenant, foo_changeset) do
{:ok, foo} ->
{:noreply, assign(socket, %{foo: foo})}
_ ->
{:noreply, assign(socket, %{input_foo_body: socket.assigns.foo.body})} # <- revert
end
end
As said, this solution allows me to revert input_foo_body
in case of DB error, however one thing is bothering me and I think is a huge smell: :input_foo_body
will not correspond to what the user types => I do not update :input_foo_body
in case of success, because the DB operation might take some time and I would sometimes lose my last input.
Even though the solution currently works, I’m pretty sure it is a wrong solution.
Any help is appreciated!