Building a Simple Counter App with Elixir and Phoenix LiveView

This guide will walk you through creating a simple counter application that demonstrates the basics of Phoenix LiveView. Step 1: Setting up a new Phoenix project First, make sure you have Elixir and Phoenix installed. Then, create a new Phoenix project: # Install Phoenix (if you haven't already) mix archive.install hex phx_new # Create a new Phoenix project with LiveView mix phx.new counter_app --live # Move into the project directory cd counter_app # Set up the database (we won't use it much, but it's required) mix ecto.setup Step 2: Create a simple counter LiveView Create a new file at lib/counter_app_web/live/counter_live.ex: defmodule CounterAppWeb.CounterLive do # Use the LiveView functionality from the web module use CounterAppWeb, :live_view # mount/3 is called when the LiveView is first rendered # It sets up the initial state of the LiveView def mount(_params, _session, socket) do # Initialize the socket with a count of 0 # assign/2 is used to set values in the socket's state {:ok, assign(socket, count: 0)} end # handle_event/3 processes events sent from the client # This function handles the "increment" event def handle_event("increment", _params, socket) do # Update the count by adding 1 # update/3 modifies an existing assign value {:noreply, update(socket, :count, &(&1 + 1))} end # This function handles the "decrement" event def handle_event("decrement", _params, socket) do # Update the count by subtracting 1 {:noreply, update(socket, :count, &(&1 - 1))} end # This function handles the "reset" event def handle_event("reset", _params, socket) do # Reset the count to 0 {:noreply, assign(socket, count: 0)} end # render/1 defines what HTML to display # It receives the socket's assigns as its argument def render(assigns) do ~H""" Simple Counter App Count: - Reset + """ end end Step 3: Add the route for our LiveView Edit lib/counter_app_web/router.ex to add a route for our counter: defmodule CounterAppWeb.Router do use CounterAppWeb, :router # Pipeline definitions (already included when you create a new project) pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_live_flash plug :put_root_layout, html: {CounterAppWeb.Layouts, :root} plug :protect_from_forgery plug :put_secure_browser_headers end pipeline :api do plug :accepts, ["json"] end # Browser routes scope "/", CounterAppWeb do pipe_through :browser # Add this line to direct the root path to our CounterLive module live "/", CounterLive end # Other route groups would go here end Step 4: Add some basic CSS Edit assets/css/app.css to add some styling for our counter: /* Add this to the bottom of the file */ /* Container for the counter application */ .counter-container { max-width: 500px; margin: 0 auto; padding: 20px; text-align: center; font-family: system-ui, sans-serif; } /* Style for the buttons */ .buttons { display: flex; justify-content: center; gap: 10px; margin-top: 20px; } .button { padding: 10px 20px; font-size: 18px; border: none; border-radius: 4px; background-color: #4a6da7; color: white; cursor: pointer; transition: background-color 0.3s; } .button:hover { background-color: #2c4a7c; } Step 5: Run the application Start the Phoenix server: mix phx.server Visit http://localhost:4000 in your browser, and you should see your counter application running! Understanding the LiveView Flow When a user visits the page: The mount/3 function is called, initializing the state with count: 0 The render/1 function generates the initial HTML When a user clicks a button: The phx-click attribute tells LiveView which event to trigger LiveView sends this event to the server through the WebSocket connection The corresponding handle_event/3 function is called on the server The state is updated accordingly The render/1 function is called again to update the HTML LiveView sends only the differences (patches) to the browser to update the DOM This is all handled automatically by LiveView, giving you real-time updates without writing any JavaScript! Next Steps To expand this application, you could: Add more complex state management Create LiveComponents for reusable UI elements Implement form validation Add persistence with Ecto and a database Congratulations! You've created your first Phoenix LiveView application.

Mar 18, 2025 - 22:53
 0
Building a Simple Counter App with Elixir and Phoenix LiveView

This guide will walk you through creating a simple counter application that demonstrates the basics of Phoenix LiveView.

Step 1: Setting up a new Phoenix project

First, make sure you have Elixir and Phoenix installed. Then, create a new Phoenix project:

# Install Phoenix (if you haven't already)
mix archive.install hex phx_new

# Create a new Phoenix project with LiveView
mix phx.new counter_app --live

# Move into the project directory
cd counter_app

# Set up the database (we won't use it much, but it's required)
mix ecto.setup

Step 2: Create a simple counter LiveView

Create a new file at lib/counter_app_web/live/counter_live.ex:

defmodule CounterAppWeb.CounterLive do
  # Use the LiveView functionality from the web module
  use CounterAppWeb, :live_view

  # mount/3 is called when the LiveView is first rendered
  # It sets up the initial state of the LiveView
  def mount(_params, _session, socket) do
    # Initialize the socket with a count of 0
    # assign/2 is used to set values in the socket's state
    {:ok, assign(socket, count: 0)}
  end

  # handle_event/3 processes events sent from the client
  # This function handles the "increment" event
  def handle_event("increment", _params, socket) do
    # Update the count by adding 1
    # update/3 modifies an existing assign value
    {:noreply, update(socket, :count, &(&1 + 1))}
  end

  # This function handles the "decrement" event
  def handle_event("decrement", _params, socket) do
    # Update the count by subtracting 1
    {:noreply, update(socket, :count, &(&1 - 1))}
  end

  # This function handles the "reset" event
  def handle_event("reset", _params, socket) do
    # Reset the count to 0
    {:noreply, assign(socket, count: 0)}
  end

  # render/1 defines what HTML to display
  # It receives the socket's assigns as its argument
  def render(assigns) do
    ~H"""
    
counter-container">

Simple Counter App

Count: <%= @count %>

buttons">
"""
end end

Step 3: Add the route for our LiveView

Edit lib/counter_app_web/router.ex to add a route for our counter:

defmodule CounterAppWeb.Router do
  use CounterAppWeb, :router

  # Pipeline definitions (already included when you create a new project)
  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {CounterAppWeb.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  # Browser routes
  scope "/", CounterAppWeb do
    pipe_through :browser

    # Add this line to direct the root path to our CounterLive module
    live "/", CounterLive
  end

  # Other route groups would go here
end

Step 4: Add some basic CSS

Edit assets/css/app.css to add some styling for our counter:

/* Add this to the bottom of the file */

/* Container for the counter application */
.counter-container {
  max-width: 500px;
  margin: 0 auto;
  padding: 20px;
  text-align: center;
  font-family: system-ui, sans-serif;
}

/* Style for the buttons */
.buttons {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 20px;
}

.button {
  padding: 10px 20px;
  font-size: 18px;
  border: none;
  border-radius: 4px;
  background-color: #4a6da7;
  color: white;
  cursor: pointer;
  transition: background-color 0.3s;
}

.button:hover {
  background-color: #2c4a7c;
}

Step 5: Run the application

Start the Phoenix server:

mix phx.server

Visit http://localhost:4000 in your browser, and you should see your counter application running!

Understanding the LiveView Flow

  1. When a user visits the page:

    • The mount/3 function is called, initializing the state with count: 0
    • The render/1 function generates the initial HTML
  2. When a user clicks a button:

    • The phx-click attribute tells LiveView which event to trigger
    • LiveView sends this event to the server through the WebSocket connection
    • The corresponding handle_event/3 function is called on the server
    • The state is updated accordingly
    • The render/1 function is called again to update the HTML
    • LiveView sends only the differences (patches) to the browser to update the DOM

This is all handled automatically by LiveView, giving you real-time updates without writing any JavaScript!

Next Steps

To expand this application, you could:

  1. Add more complex state management
  2. Create LiveComponents for reusable UI elements
  3. Implement form validation
  4. Add persistence with Ecto and a database

Congratulations! You've created your first Phoenix LiveView application.