#185: Phoenix LiveView Tutorial Part 9
Currently in our game, when a player submits a guess there’s no feedback in the UI to indicate whether the guess was right or wrong. Let’s open our WordLive.Index LiveView and if we scroll down to our handle_event callback that handles the “enter” event. We see where in the last episode we set up some IO.puts statements to log the guess results. In this episode we’ll update this to display the results of the guess on the page for the user to see. To do that, we’ll create different functions that will handle each different scenario.
For a correct guess we’ll create a new function called handle_correct_guess that will take the socket and the solve. Then we’ll create a new function called handle_invalid_guess that will take the socket and the error_message. Another function handle_game_over that will take the socket and solve and finally, handle_incorrect_guess that will take the socket. Adding a different function to handle the different scenarios will make it easy for us to update the socket and push different kinds of events based on the result of the guess. We wont need the IO.puts statements going forward so let’s remove those.
Now let’s add these functions. We’ll create the private handle_correct_guess function below. And let’s use flash messages to show the feedback. We’ll take the socket and pipe it into put_flash and the kind of message for this will be :correct - we can pattern match on this to update how the flash message looks based on the result of the guess - and then a message to display, saying that the “solve” was the correct word.
Let’s follow the same pattern for the handle_invalid_guess function only now we’ll use a different kind of message: :error. And a different message - the error_message we passed in to the function. Then we’ll add the handle_game_over function, updating the kind of flash message to :game_over and the message telling the user what the correct guess was.
Now for the last of these functions handle_incorrect_guess. When an incorrect guess is submitted, we increment the current_guess assign. Let’s move this into the handle_incorrect_guess function. We’ll pass the guess_row into the function. Then let’s update the socket in the handle_incorrect_guess and we’ll update the message. And let’s use :incorrect for the kind of flash message. Also, the solve being used is a struct, so we’ll need to update them to return the name field.
lib/werdle_web/live/word_live/index.ex...
def handle_event("enter", _params, socket) do
changeset = socket.assigns.changeset
guess_row = socket.assigns.current_guess
solve = socket.assigns.solve
with {:ok, _changeset} <- Game.validate_guess(changeset, guess_row),
{:correct, _changeset} <- Game.check_guess_correctness(changeset, guess_row, solve.name) do
{:noreply, handle_correct_guess(socket, solve)}
else
{:error, error_message} ->
{:noreply, handle_invalid_guess(socket, error_message)}
{:incorrect, _changeset} when guess_row == 5 ->
{:noreply, handle_game_over(socket, solve)}
{:incorrect, _changeset} ->
{:noreply, handle_incorrect_guess(socket, guess_row)}
end
end
defp handle_correct_guess(socket, solve) do
socket
|> put_flash(:correct, "#{String.upcase(solve.name)} was the correct word")
end
defp handle_invalid_guess(socket, error_message) do
socket
|> put_flash(:error, error_message)
end
defp handle_game_over(socket, solve) do
socket
|> put_flash(:game_over, "The solve was #{String.upcase(solve.name)}")
end
defp handle_incorrect_guess(socket, guess_row) do
socket
|> assign(:current_guess, guess_row + 1)
|> put_flash(:incorrect, "Try another word")
end
...
Now we need to update our flash component to handle these new kinds of messages we’re using. Let’s open the core_components.ex module that contains these components and move down to the flash_group component function. And update it to include flash components for our new kinds of flash messages. We’ll pattern matching on :game_over, :incorrect, and :correct.
Then we’ll go to the flash component function and update the :kind attribute to include the new kinds of flash messages we’ve added. Inside the function we’ll update the classes that are used for our different kinds of flash messages we’ll check if the message is equal to :game_over, :incorrect, or :correct. Then if it is we’ll display different CSS styles depending on the kind of message. I’ll go ahead and paste those in.
Below it let’s add a different icon for our different results there’s already one for the :error message. Let’s add one if it’s :game_over and for that we’ll use the face frown icon. And then a different one for the :incorrect message.
Module path: lib/werdle_web/components/core_components.ex
...
attr :kind,
:atom,
values: [:info, :error, :game_over, :incorrect, :correct],
doc: "used for styling and flash lookup"
...
def flash(assigns) do
...
~H"""
<div
...
class={[
"fixed mt-4 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-80 sm:w-96 z-50 rounded-lg p-3 ring-1",
@kind == :info && "bg-emerald-50 text-emerald-800 ring-emerald-500 fill-cyan-900",
@kind == :error && "bg-rose-50 text-rose-900 shadow-md ring-rose-500 fill-rose-900",
@kind == :game_over && "bg-slate-50 text-slate-900 shadow-md ring-slate-900 fill-slate-900",
@kind == :incorrect && "bg-rose-50 text-rose-900 shadow-md ring-rose-500 fill-rose-900",
@kind == :correct && "bg-green-50 text-green-900 shadow-md ring-green-500 fill-green-900"
]}
{@rest}
>
<p :if={@title} class="flex items-center gap-1.5 text-sm font-semibold leading-6">
<.icon :if={@kind == :info} name="hero-information-circle-mini" class="h-4 w-4" />
<.icon :if={@kind == :error} name="hero-no-symbol" class="h-4 w-4" />
<.icon :if={@kind == :game_over} name="hero-face-frown" class="h-4 w-4" />
<.icon :if={@kind == :incorrect} name="hero-no-symbol" class="h-4 w-4" />
<%= @title %>
</p>
...
</div>
"""
end
...
def flash_group(assigns) do
...
<.flash kind={:error} title="Bad guess" flash={@flash} />
<.flash kind={:game_over} title="Game over" flash={@flash} />
<.flash kind={:incorrect} title="Incorrect guess" flash={@flash} />
<.flash kind={:correct} title="You won 🎉" flash={@flash} />
...
end
...
Ok, with that let’s go back to the browser and now when we submit an invalid guess we get a flash message letting us know. Then if we try to submit a valid guess, it tells us the guess was incorrect and to try another word.
Once we submit a guess, the next guess appears on the next row in our grid. And if we get lucky and guess correctly. Perfect! We see the flash message for a correct guess is displayed.