Home Posts Post Search Tag Search

LiveView 24 - Chapter 8: Your Turn
Published on: 2026-01-16 Tags: elixir, Blog, LiveView, Html/CSS, Phoenix, queries

Your Turn

We now have added in a dashboard with an interactive bar chart that will allows an admin to see the average ratings for all the products based of age groups. We even added in a using macro that will allow a dev to simply add in a use block to be able to leverage the bar chart that we made.

Give it a Try

We want to add a by gender drop down to do the same thing that we did for the age group.

To do this we will need to take a few steps.

Update the query.ex to have the new query based off gender

  defp filter_by_gender(query \\ base(), filter) do
    query
    |> apply_gender_filter
  end

  defp apply_gender_filter(query, "prefer not to say") do
    query
    |> where([p, r, u, d], d.gender = "prefer not to say")
  end

  defp apply_gender_filter(query, "other") do
    query
    |> where([p, r, u, d], d.gender = "other")
  end

  defp apply_gender_filter(query, "female") do
    query
    |> where([p, r, u, d], d.gender = "female")
  end

  defp apply_gender_filter(query, "male") do
    query
    |> where([p, r, u, d], d.gender = "male")
  end

  defp apply_gender_filter(query, _filter) do
    query
  end

Update the catalog.ex to use the new query

  @doc """
  Returns all the ratings for a set of products based off the gender
  or age group that we filter it with.

  ## Examples

    iex> products_with_average_ratings(%{gender_filter: "male"})
    [{"Backgammon", 3.0},
    {"Checkers", 4.0},
    {"Chess", 5.0},
    {"Go", 2.0}]

    iex> products_with_average_ratings(%{gender_filter: "15 to 25})
    [{"Backgammon", 3.0},
    {"Checkers", 4.0},
    {"Chess", 5.0},
    {"Go", 2.0}]
  """
  def products_with_average_ratings(%{
        gender_filter: gender_filter
      }) do
    Product.Query.with_average_ratings()
    |> Product.Query.join_users()
    |> Product.Query.join_demographics()
    |> Product.Query.filter_by_gender(gender_filter)
    |> Repo.all()
  end

Add in a new drop-down for the gender

<.form
    for={%{}}
    as={:gender_filter}
    phx-change="gender_filter"
    phx-target={@myself}
    id="gender-form"
>
    <label class="label">
    <span class="label-text text-sm">By gender:</span>
    </label>
    <select
    name="gender_filter"
    id="gender_filter"
    class="select select-bordered select-sm w-full"
    >
    <%= for gender_group <-
["all", "male", "female", "other", "prefer not to say"] do %>
        <option value={gender_group} selected={@gender_filter == gender_group}>
        {gender_group}
        </option>
    <% end %>
    </select>
</.form>

Add in a new event for the “gender-filter”

@impl true
  def handle_event("gender_filter", %{"gender_filter" => gender_group}, socket) do
    {:noreply,
     socket
     |> assign_age_group_filter()
     |> assign_gender_filter(gender_group)
     |> assign_products_with_average_ratings()
     |> assign_dataset()
     |> assign_chart()
     |> assign_chart_svg()}
  end

  def assign_gender_filter(socket, gender_group) do
    socket
    |> assign(:gender_filter, gender_group)
  end

  def assign_gender_filter(socket) do
    socket
    |> assign(:gender_filter, "all")
  end

  def assign_age_group_filter(socket, age_group) do
    socket
    |> assign(:age_group_filter, age_group)
  end

  def assign_age_group_filter(socket) do
    socket
    |> assign(:age_group_filter, "all")
  end

  def assign_products_with_average_ratings(
        %{assigns: %{gender_filter: gender_filter, age_group_filter: "all"}} =
          socket
      ) do
    assign(
      socket,
      :products_with_average_ratings,
      get_products_with_average_ratings(%{gender_filter: gender_filter})
    )
  end

  def assign_products_with_average_ratings(
        %{assigns: %{gender_filter: "all", age_group_filter: age_group_filter}} =
          socket
      ) do
    assign(
      socket,
      :products_with_average_ratings,
      get_products_with_average_ratings(%{age_group_filter: age_group_filter})
    )
  end