← All series

Series contents

Log in to track your progress

  1. 1. Simple Phoenix LiveView App: Setup Episode
  2. 2. Simple Phoenix LiveView App: Planning DB Schemas Episode
  3. 3. Simple Phoenix LiveView App: Upgrade to LiveView 0.5.1 Episode
  4. 4. Simple Phoenix LiveView App: Socket Session info, CSRF & .leex Episode
  5. 5. Simple Phoenix LiveView App: Scaffolding Users & Content Episode
  6. 6. Simple Phoenix LiveView App: PubSub & Index Episode
  7. 7. Simple Phoenix LIveView App: Show & Edit Pages Episode
  8. 8. Simple Phoenix LiveView App: Upgrade LiveView to v0.8.1 Episode
  9. 9. Simple Phoenix LiveView App: Fonts, logos and sass Episode
  10. 10. Simple Phoenix LiveView App: Markdown show notes Episode
  11. 11. Simple Phoenix LiveView App: The Podcast Listing Page Episode
  12. 12. Simple Phoenix LiveView App: Upgrade LiveView to v0.12.1 Episode
  13. 13. How I add auth to Phoenix LiveView apps Episode
  14. 14. Simple Phoenix LiveView App: planning comments Episode
  15. 15. Showing comment counts on the index page (Simple Phoenix LiveView App) Episode
  16. 16. Simple Phoenix LiveView app: Embedded comments form Episode
  17. 17. Passing redirect URLs + fragments Episode
  18. 18. Simple Phoenix LiveView App: Series Complete! Episode

Showing comment counts on the index page (Simple Phoenix LiveView App)

This screencast goes over how to get comment counts for each podcast (or blog post, etc) and show them on the listing page.

One way to do this would be to preload all the comments. That's good for a show page for a single podcast, but it's not very efficient to load every comment on every podcast for the index page.

Instead, we'll add a virtual field comment_count to the podcast schema and then write a more complex Ecto query that will retrieve comment counts but not preload each individual comment.

A virtual field

First, add a virtual field to the podcast schema for comment_count:

schema "podcasts" do
  field :audio_url, :string
  field :comment_count, :integer, default: 0, virtual: true
  field :is_published, :boolean, default: false
  field :notes_html, :string
  field :notes_md, :string
  field :subtitle, :string
  field :title, :string
  has_many(:comments, Reactor.Content.Comment)

  timestamps()
end

The field is virtual since we don't need to store anything in the database for it and it will default to zero so we can depend on it being an integer.

A view helper

When we display the number of comments on a podcast, we want a nicely formatted string that handles singular and plural numbers in a reasonable way. To do that, we'll create a helper function in podcast_view.ex:

defmodule ReactorWeb.PodcastView do
  use ReactorWeb, :view

  def comment_count_str(n) do
    case n do
      0 -> "(no comments)"
      1 -> "(1 comment)"
      n -> "(#{n} comments)"
    end
  end
end

Then, instead of calling to_string on whatever integer value is in a comment count field, we can just call comment_count_str in our template and have a reasonable display for the number of comments.

Listing podcasts with comment counts

In our context module, we'll need a more complex list_podcasts function in order to populate the virtual comments_count field in each podcast.

  def list_podcasts do
    comment_counts = get_comment_counts()

    Podcast
    |> order_by(desc: :id)
    |> Repo.all()
    |> Enum.map(& %{&1 | comment_count: comment_counts[&1.id] || 0})
  end

  def get_comment_counts do
    from(p in Podcast,
      join: c in assoc(p, :comments),
      group_by: p.id,
      select: {p.id, count(c.id)}
    )
    |> Repo.all()
    |> Enum.into(%{})
  end

This is a three-step process. First we create a mapping of podcast IDs to comment counts, e.g. %{1 => 3, 2 => 4, 3 => 4}. Then, we retrieve the podcast listing without comments. Finally we map over the podcasts and update their comment_counts, using the mapping from the first step as a look-up table.

(Source code available for premium members)

Next episode: Adding comments

Open standalone page ↗

No Comments