Elixir
In 2011, a new programming language appeared with a simple focus in mind: Making a programming language concurrent, elegant, easy, blasting fast, and powered by one of the monsters ever built, Erlang.
Elixir is a functional language built on top of Erlang, providing a delightful syntax pretty similar to Ruby, it is designed to scale tons of thousands of threads concurrently and enabling communication between them via messages. Elixir and erlang also promote a really nice expression things will go wrong
and this is because it is designed to fail, offering a lot of mechanisms such as supervisors restarting particular parts or threads of the system instead of a complete explosion.
Phoenix
Phoenix is to Elixir what Rails is to Ruby: an amazingly fast web framework for building web applications without compromising scalability or maintainability.
By taking advantage of Phoenix speed, channels, and HTTP 2.0 implementation, Phoenix's builders came out with a cool library for Phoenix called LiveView
which provides a really cool way to make reactive views with 0 Javascript and just Elixir.
Let's stop talking and let's write some code!
Having in mind that you already installed NodeJS in your computer, we first want to have Elixir installed
brew install elixir
Mix
is a build tool that ships with Elixir that provides tasks for creating, compiling, testing your application, managing its dependencies and much more.
Now that we have it installed, let's install Phoenix
mix archive.install hex phx_new 1.4.0
Now we are all set to create our new Phoenix app
mix phx.new reactivity
A lot of things are going to start happening so, when mix asks us to Fetch and install dependencies?
, just type y
.
Now, let's set up our database and start our server
cd reactivity
mix ecto.create
mix phx.server
And know in our browser, we can go to localhost:4000
Now we are ready to set up LiveView
First, let's open our mix.exs
file and add LiveView as a dependency and then run mix deps.get
def deps do
[
...
{:phoenix_live_view, "~> 0.10.0"},
{:floki, ">= 0.0.0", only: :test}
]
end
After getting all the dependencies, let's restart our server by pressing ctr+c
twice and then mix phx.server
Now, let's open config/confix.exs
and add out endpoint configuration. You can generate your own salt by running mix phx.gen.secret 32
config :reactivity, ReactivityWeb.Endpoint,
...
live_view: [
signing_salt: "YOUR_SALT_GOES_HERE"
]
Now we need to configure our browser pipeline:
# lib/my_app_web/router.ex
import Phoenix.LiveView.Router
pipeline :browser do
...
plug :fetch_session
- plug :fetch_flash
+ plug :fetch_live_flash
end
Then, add the following imports to our web file in lib/reactivity_web.ex
:
# lib/reactivity_web.ex
def controller do
quote do
...
import Phoenix.LiveView.Controller
end
end
def view do
quote do
...
import Phoenix.LiveView.Helpers
end
end
def router do
quote do
...
import Phoenix.LiveView.Router
end
end
Then, we will configure our endpoint:
# lib/reactivity_web/endpoint.ex
defmodule ReactivityWeb.Endpoint do
use Phoenix.Endpoint
# ...
socket "/live", Phoenix.LiveView.Socket,
websocket: [connect_info: [session: @session_options]]
# ...
end
Now, let's add LiveView JavaScript dependency:
{
"dependencies": {
"phoenix": "file:../deps/phoenix",
"phoenix_html": "file:../deps/phoenix_html",
"phoenix_live_view": "file:../deps/phoenix_live_view"
}
}
And let's install it:
npm install --prefix assets
Now, let's enable the socket communication:
// assets/js/app.js
import {Socket} from "phoenix"
import LiveSocket from "phoenix_live_view"
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}});
liveSocket.connect()
And finally, and optionally, you can add the default CSS:
/* assets/css/app.css */
@import "../../deps/phoenix_live_view/assets/css/live_view.css";
Perfect! We can now restart our server and check if everything is OK!
Controller
Now that we have everything set up, we can start by writing our first Controller, which will have the specific action for our route and will render our LiveView
!
Let's go ahead and create a new file under /lib/reactivity_web/controllers/
called to_do_controller.ex
and add the following:
defmodule ReactivityWeb.ToDoController do
use ReactivityWeb, :controller
def index(conn, _params) do
live_render(conn, ReactivityWeb.ToDoView)
end
end
Then, add the route to lib/reactivity_web/router.ex
scope "/", ReactivityWeb do
pipe_through :browser
get "/", PageController, :index
get "/todo", ToDoController, :index
end
LiveView
Add a new folder index /lib/reactivity_web/
called live
and a file inside it called to_do_view.ex
with the next content:
defmodule ReactivityWeb.ToDoView do
use Phoenix.LiveView
# Method that returns the HTML code that will be rendered
def render(assigns) do
~L"""
<div>
<span> <%= format_date(@time) %></span>
</div>
"""
end
# This is the first function that gets called once the live view is loaded
def mount(_session, _, socket) do
# Check if the socket is correctly connect we send a tick in the server and falls in handle_info(:tick, process)
if connected?(socket), do: Process.send_after(self(), :tick, 1000)
# Here we assign all the variables needed for our view
{:ok, assign(socket, time: :calendar.local_time())}
end
# This function receives the tick event and the socket that triggered the event
def handle_info(:tick, socket) do
# So we send another tick after 1 second
Process.send_after(self(), :tick, 1000)
# And reply to our view with the local time, which ends up in rendering the view again
{:noreply, assign(socket, time: :calendar.local_time())}
end
# Helper to format the date into a readable Hour
def format_date(date) do
{_, {h, m, s}} = date
"#{h}:#{m}:#{s}"
end
end
And now, if we go to localhost:4000/todo
, we'll see
As you can see, the view is being rendered without making any kind of event from the browser: the server knows that every second a :tick
event is being triggered and the handle_info(:tick, socket)
function handles this event and updates the state
or assigns
making the view render again.
Now, let's add some more code in order to build a simple To-Do list.
First, we'll add a new variable called todos
:
def mount(_session, _, socket) do
if connected?(socket), do: Process.send_after(self(), :tick, 1000)
{:ok, assign(socket, time: :calendar.local_time(), todos: [])}
end
Add a form and a loop for rendering the tasks in our To-Do list. Here's the form will an option called phx_submit
and a value of :save
: this means that, whenever the form is submitted, LiveView
will trigger an event called :save
with the data in the form.
def render(assigns) do
~L"""
<div>
<span> <%= format_date(@time) %></span>
<%= f = form_for :todo, "#", [phx_submit: :save] %>
<%= label f, :task %>
<%= text_input f, :task %>
<%= submit "Save" %>
</form>
<ul>
<%= for task <- @todos do %>
<li><%= task %></li>
<% end %>
</ul>
</div>
"""
end
Now to handle that event, let's add a new handle_event
function:
#This function will handle the save event on submit form
def handle_event("save", %{"todo" => %{"task" => task}}, socket) do
# And we will add the new task to out tasks array
{:noreply, update(socket, :todos, &([task |&1]))}
end
And now in the browser, you will see:
And that's it!
No JavaScript needed and a whole world of opportunities around Elixir, Phoenix and this amazing library LiveView. There's a ton of things you can build with this and you don't need a lot of languages and stuff trying to interact with each other. Elixir has been growing along with its community, so I think it's the best time to start learning it and build amazing stuff with it.
Top comments (0)