#183: Phoenix LiveView Tutorial Part 7
Now that we can add letters to our guess we need a way to remove them. In this episode let’s update our game to allow players to remove letters. Back in our code, let’s open the keycap_component.ex and in the last episode we added a phx-click binding for the “letter”.
Let’s add another phx-click binding to the HTML we’re using for the backspace button. We’ll call our event “backspace”.
Template path: lib/werdle_web/components/game_board/keycap_component.ex
...
@impl true
def render(%{keycap_value: "backspace"} = assigns) do
~H"""
<kbd id={@id} phx-click="backspace" class="kbd kbd-lg bg-gray-500 text-slate-200 cursor-default rounded-md border-transparent">
...
"""
end
...
Now we’ll need to handle that event in our WordLive.Index LiveView, so let’s open that. And add the callback, pattern matching on the event “backspace”. We won’t need any params for this callback so let’s ignore them. Inside the function, we’ll get the changeset from the assigns. As well as the row of the current guess. And then return {:noreply, socket}.
We need to take our changeset and guess_row and build a way to remove the last character from the current guess.
lib/werdle_web/live/word_live/index.ex...
def handle_event("backspace", _params, socket) do
changeset = socket.assigns.changeset
guess_row = socket.assigns.current_guess
# remove the last character from the current guess
{:noreply, socket}
end
...
To do that let’s create a function in our Game module that’s responsible for removing the last letter for the current guess. We’ll create a new public function called remove_last_char that will take that changeset and guess_row. Then we’ll take the guess_row and use it to get the guess_field. With that let’s call Changeset.get_change with the changeset and the guess_field, returning an empty list for the default. This will give us a list of letters we’ll assign to the current_guess.
Then to remove the last letter from the list, we’ll call List.delete_at passing in the current_guess list, and then -1.
Now that we have an updated_guess let’s update our changeset with it. We’ll call changeset.changes and then pipe that into Map.merge to update the guess_field with our updated_guess list. Then let’s return a changeset by piping that into change_guesses.
lib/werdle/game.ex...
def remove_last_char(changeset, guess_row) do
guess_field = guess_field(guess_row)
current_guess = Changeset.get_change(changeset, guess_field, [])
updated_guess = List.delete_at(current_guess, -1)
changeset.changes
|> Map.merge(%{guess_field => updated_guess})
|> change_guesses()
end
...
Great, with that we can go back to our LiveView and update our changeset assign by calling Game.remove_last_char. Now when we remove a letter from a guess it will remove the last character from the current guess field in the changeset. That changeset will be assigned to the socket and our components should update.
lib/werdle_web/live/word_live/index.ex...
def handle_event("backspace", _params, socket) do
changeset = socket.assigns.changeset
guess_row = socket.assigns.current_guess
socket =
socket
|> assign(:changeset, Game.remove_last_char(changeset, guess_row))
{:noreply, socket}
end
...
Let’s test it out. We’ll go back to the browser and we can add letters to our guess, but if we make a mistake and need to fix it. Great! The letters are removed and we can update our guesses.