DEV Community

Cover image for How To Build a [Counter with Elixir, Phoenix, LiveView and Tailwind CSS] | No Javascript
Anthony Gonzalez
Anthony Gonzalez

Posted on

How To Build a [Counter with Elixir, Phoenix, LiveView and Tailwind CSS] | No Javascript

 
 

 
 

Learn how to use Elixir/Phoenix, to create a counter without javascript, only using Elixir with the help of Phoenix LiveView, and Tailwind CSS for the user interface.

Step 1:

Let's create a fresh elixir/phoenix new project by going to the command line and typing the following in your desired directory:

$ mix phx.new counter --no-ecto --no-gettext --no-mailer --no-dashboard && cd counter

Step 2:

Let's add and configure Tailwind CSS, go to the website https://hex.pm and search for the tailwind library to grab the latest version, so you can copy and that to your mix config file, at the time of the making of this tutorial the latest version is 0.1.5, add the following to your project dependencies inside your mix.exs file:

{:tailwind, "~> 0.1.5"}

Then in the command line type in $ mix deps.get && mix tailwind.install to fetch your new dependency and install tailwind. Back in your mix.exs file, under aliases, add the following:

"assets.deploy": ["tailwind default --minify", ..., "phx.digest"]

Go to your config/config/exs file and add the following configuration:

config :tailwind,
  version: "3.0.10",
  default: [
    args: ~w(
      --config=tailwind.config.js
      --input=css/app.css
      --output=../priv/static/assets/app.css
    ),
    cd: Path.expand("../assets", __DIR__)
  ]
Enter fullscreen mode Exit fullscreen mode

Go to your config/dev.exs file and add the following to your watchers:

tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}
Enter fullscreen mode Exit fullscreen mode

Step 3:

Add the following folder under test/counter_web:

live

Add the following file to that newly created folder:

page_live_test.exs

To that newly created file test/counter_web/live/page_live_test.exs add the following tests:

defmodule CounterWeb.PageLiveTest do
  use CounterWeb.ConnCase

  import Phoenix.LiveViewTest

  test "disconnected and connected render", %{conn: conn} do
    {:ok, page_live, disconnected_html} = live(conn, "/")
    assert disconnected_html =~ "0"
    assert render(page_live) =~ "0"
  end

  test "increment event and decrement", %{conn: conn} do
    {:ok, page_live, _html} = live(conn, "/")
    assert render_click(page_live, :inc, %{}) =~ "1"
    assert render_click(page_live, :inc, %{}) =~ "2"
    assert render_click(page_live, :inc, %{}) =~ "3"
    assert render_click(page_live, :dec, %{}) =~ "2"
    assert render_click(page_live, :dec, %{}) =~ "1"
    assert render_click(page_live, :dec, %{}) =~ "0"
  end

  test "clear event", %{conn: conn} do
    {:ok, page_live, _html} = live(conn, "/")
    assert render_click(page_live, :inc, %{}) =~ "1"
    assert render_click(page_live, :clear, %{}) =~ "0"
  end
end
Enter fullscreen mode Exit fullscreen mode

If you run those tests by going to the command line and typing mix test test/counter_web/live they should fail of course.

Step 4:

Open your lib/counter_web/router.ex file and remove the root path and change it to the following:

  scope "/", CounterWeb do
    pipe_through :browser

    live "/", PageLive
  end
Enter fullscreen mode Exit fullscreen mode

Run the server with the following command in your terminal:

$ iex -S mix phx.server

Open your lib/counter_web/templates/layout/root.html.heex and remove the header nav, your html body tag should look like the following:

  <body>
    <%= @inner_content %>
  </body>
Enter fullscreen mode Exit fullscreen mode

To your lib/counter_web/templates/layout/live.html.heex file, add the following css class to your main tag:

<main class="container mx-auto max-w-full">
Enter fullscreen mode Exit fullscreen mode

Add the following folder to lib/counter_web:

live

Add the following file to that newly created live folder:

page_live.ex

Add the following to that newly created file lib/counter_web/live/page_live.ex:

defmodule CounterWeb.PageLive do
  use CounterWeb, :live_view
end
Enter fullscreen mode Exit fullscreen mode

Under lib/counter_web/live add the following file:

page_live.html.heex

Add the following to that newly created lib/counter_web/live/page_live_html.heex file:

<div class="flex flex-col items-center justify-center h-screen bg-gray-200">
  <h1 class="text-5xl font-medium text-gray-700">Counter</h1>

  <span class="m-5 text-9xl">
    0
  </span>

  <section> 
    <button class="text-white text-4xl bg-indigo-600 px-6 py-4 rounded hover:bg-indigo-900">-</button>

    <button class="m-10 text-white text-4xl bg-indigo-900 px-6 py-4 rounded hover:bg-indigo-500">clear</button>

    <button class="text-white text-4xl bg-indigo-600 px-6 py-4 rounded hover:bg-indigo-900">+</button>
  </section>
</div>
Enter fullscreen mode Exit fullscreen mode

Step 5:

Let's add our liveview mount function and assign the default number.

To lib/counter_web/live/page_live.ex file add the following function:

  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(number: 0)}
  end
Enter fullscreen mode Exit fullscreen mode

Then change the number 0 to our new assign variable in our lib/counter_web/live/page_lve.html.heex file, inside our span tag:

  <span class="m-5 text-9xl">
    <%= @number %>
  </span>
Enter fullscreen mode Exit fullscreen mode

Step 6:

Inside our lib/counter_web/live/page_lve.html.heex file, add the following click event binding to our increase button:

<button phx-click="inc" class="...">+</button>
Enter fullscreen mode Exit fullscreen mode

Then to our lib/counter_web/live/page_live.ex file let's add the following function to handle that event:

  def handle_event("inc", _params, socket) do
    {:noreply,
     socket
     |> update(:number, &(&1 + 1))}
  end
Enter fullscreen mode Exit fullscreen mode

Step 7:

Inside our lib/counter_web/live/page_lve.html.heex file, add the following click event binding to our decrease button:

<button phx-click="dec" class="...">-</button>
Enter fullscreen mode Exit fullscreen mode

To our lib/counter_web/live/page_live.ex file let's add the following function to handle the decrease event:

  def handle_event("dec", _params, socket) do
    {:noreply,
     socket
     |> update(:number, &max(0, &1 - 1))}
  end
Enter fullscreen mode Exit fullscreen mode

Step 8:

Let's add the following click event binding to our clear button inside our lib/counter_web/live/page_lve.html.heex file:

<button phx-click="clear" class="...">clear</button>
Enter fullscreen mode Exit fullscreen mode

To our lib/counter_web/live/page_live.ex file let's add the following function to handle the clear event:

  def handle_event("clear", _params, socket) do
    {:noreply, socket |> assign(number: 0)}
  end
Enter fullscreen mode Exit fullscreen mode

Go to http://localhost:4000 to test your application manually as a user, and if you go to the command line and run the tests with mix test test/counter_web/live they should pass with no failure.

Conclusion

That's all folks, we went through the simple steps to set up Tailwind CSS with your phoenix applications, and how to handle click events with Phoenix LiveView over sockets without the need of using Javascript code, the Javascript is handled nicely in the background for us by the LiveView library. Thank you so much for your time, I really appreciate it.

 
 

Join The Elixir Army

Discussion (0)