Subscribe to access all episodes. View plans →
Published April 2, 2019
Phoenix 1.4
Elixir 1.7
View source on GitHub
The much anticipated Phoenix LiveView project is now public. In this episode let’s test it out by updating our record application to use Phoenix LiveView.
When we’re finished, we’ll be able to edit our album summaries right from the page and when an album is updated, the changes will be immediately broadcasted to anyone looking at the albums. LiveView is under active development, so there may be changes to the API before the official release.
Let’s get started by configuring our application to use Phoenix LiveView. As of this recording Phoenix LiveView is not on Hex, so we’ll need to get it from GitHub. Let’s open our Mixfile and we’ll phoenix_live_view
to our list of dependencies.
mix.exs
...
defp deps do
...
{:phoenix_live_view, github: "phoenixframework/phoenix_live_view"},
...
end
...
Then let’s go to the command line and install it.
$ mix deps.get
...
Then we’ open our dev.exs
and we’ll update our Endpoint
config to include a signing salt, which Phoenix will use to sign messages between the server and the client. To generate our our signing salt let’s go to the command line and run mix phx.gen.secret 32
.
$ mix phx.gen.secret 32
NWuVyBnxDXrRoajCwFlBqIGBjl4bHygi
Then let’s copy it and we’ll include it as the signing salt.
config/dev.exs
...
config :teacher, TeacherWeb.Endpoint,
http: [port: 4000],
live_view: [
signing_salt: "NWuVyBnxDXrRoajCwFlBqIGBjl4bHygi"
],
...
We’ll also want to have our LiveView views live reloaded in development. So let’s go to our live_reload
section of the config and since by convention live views live in the live
directory let’s add an additional pattern to our live_reload config here.
config/dev.exs
...
config :teacher, TeacherWeb.Endpoint,
live_reload: [
patterns: [
...
~r{lib/teacher_web/live/.*(ex)$}
]
]
...
LiveView also has its own templates, so we’ll need to update our application to handle them. We’ll open our config.exs
and update our configuration to include LiveView template engine, which use the extension .leex
config/config.exs
...
config :phoenix,
template_engines: [leex: Phoenix.LiveView.Engine]
...
Then we’ll need to open our router.ex
and add the LiveView.Flash
plug after :fetch_flash
.
lib/teacher_web/router.ex
...
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug Phoenix.LiveView.Flash
...
end
...
Now let’s open our teacher_web.ex
module and in the view we’ll import the Phoenix.LiveView.live_render/2
and Phoenix.LiveView.live_render/3
functions. Then in the router we’ll import the Phoenix.LiveView.Router
.
lib/teacher_web.ex
...
def view do
quote do
...
import Phoenix.LiveView, only: [live_render: 2, live_render: 3]
end
end
def router do
quote do
...
import Phoenix.LiveView.Router
end
end
...
We’ll want to expose a LiveView socket. So let’s open our endpoint.ex
module and add it.
lib/teacher_web/endpoint.ex
...
socket "/live", Phoenix.LiveView.Socket
...
Then we’ll need to include the Phoenix LiveView NPM dependency. So let’s open our package.json
and include it.
assets/package.json
...
"dependencies": {
"phoenix": "file:../deps/phoenix",
"phoenix_html": "file:../deps/phoenix_html",
"phoenix_live_view": "file:../deps/phoenix_live_view"
},
...
Once we’ve added it, let’s go to the command line and cd into our assets directory and then run npm install
get our new dependency:
$ cd assets
$ npm install
...
$ cd ../
Now we need to enable connecting to our LiveView socket. To do that we’ll open our app.js
and import LiveSocket
from phoenix_live_view
. Then we’ll assign a new LiveSocket using the “/live” path we created and connect to it. With that our application should be all set up and ready using LiveView. And what’s great is that we’re done writing JavaScript - this is all the JavaScript we’ll need for the whole series.
assets/js/app.js
...
import LiveSocket from "phoenix_live_view"
let liveSocket = new LiveSocket("/live")
liveSocket.connect()
Currently, there are two ways to serve Live Views. Let’s open our router.ex
and we can serve a LiveView directly from the router using the live
macro, giving it a path and a LiveView to use.
Ore we can render our Live View from our existing controller with LiveView.Controller.live_render
. Lets use this method.
We’ll open our album_controller.ex
and let’s update our existing index
action to use the live_render
function. It will take our connection the name of the view. We’ll need to create this, but let’s call it TeacherWeb.AlbumLive.Index
Then we can include any session data and let’s remove our call to Recordings.list_albums
here. We’ll add it to our LiveView in a minute.
lib/teacher_web/controllers/album_controller.ex
...
def index(conn, _params) do
LiveView.Controller.live_render(conn, TeacherWeb.AlbumLive.Index, session: %{})
end
...
Now we need to define our LiveView module. Since LiveView modules live in the live
directory by convention, let’s create a new directory in teacher_web
named live
Then let’s create an album_live
directory and inside of that we’ll create our index.ex
module.
Then we can define our module and LiveView modules use Phoenix.LiveView
.
lib/teacher_web/live/album_live/index.ex
defmodule TeacherWeb.AlbumLive.Index do
use Phoenix.LiveView
end
A Phoenix LiveView module requires two callbacks: mount
, which is invoked after a client connects. mount
will take any session data, which we’ll ignore since we wont be using it and the socket and render
which generates the HTML for the client and takes our socket assigns
.
Let’s go back to mount
and we need it to return an OK tuple, with the second element being the socket. Now we’ll define what we want our LiveView to render. To start let’s go ahead and define our HTML right in the render
function, which we can do with the ~L
sigil and let’s just return a simple message here: “Greetings from Live View”.
lib/teacher_web/live/album_live/index.ex
defmodule TeacherWeb.AlbumLive.Index do
use Phoenix.LiveView
def mount(_session, socket) do
{:ok, socket}
end
def render(assigns) do
~L"""
Greetings from Live View
"""
end
end
Now let’s see if everything is working. We’ll start our server.
$ mix phx.server
...
Opening our browser it looks like we have an error - our live_render
function is undefined.
Let’s go back to the controller and our LiveView
module is missing alias. Let’s add it above with alias Phoenix.LiveView
. Since we’re adding an alias for that, let’s go ahead and alias our TeacherWeb.AlbumLive.Index
module as well so we can call it without the prefix. Now let’s see if our changes worked.
lib/teacher_web/controllers/album_controller.ex
...
alias Phoenix.LiveView
alias TeacherWeb.AlbumLive.Index
def index(conn, _params) do
LiveView.Controller.live_render(conn, Index, session: %{})
end
...
We’ll go back to the browser and if we reload the page - it loads and our message is being displayed - “Greetings from Live View.”
Now that we have our Live View working, let’s update it to render our albums.
We’ll go back to our AlbumLive.Index
module. Earlier we removed our Recordings.list_albums
function from our album_controller.ex
. Let’s go ahead and call it here from our mount
function and let’s alias our Recordings
module so we can call it without the prefix.
Now that we have our albums, we’ll want to add them to our socket assigns. We can use the assign
function here to merge data into our socket assigns. With our albums included in the assigns
here, they’ll now be available in our render
function. Let’s go head and update our render
function to render our album’s index.html
template. We’ll call AlbumView.render
passing in the index.html
template and the assigns and let’s also add an alias for our AlbumView
so we can call it without the prefix.
lib/teacher_web/live/album_live/index.ex
defmodule TeacherWeb.AlbumLive.Index do
use Phoenix.LiveView
alias Teacher.Recordings
alias TeacherWeb.AlbumView
def mount(_session, socket) do
albums = Recordings.list_albums()
{:ok, assign(socket, albums: albums)}
end
def render(assigns) do
AlbumView.render("index.html", assigns)
end
end
Now earlier when we were setting up our application to use LiveView, we added support for LiveView templates with the .leex
extension.
We’ll need to rename the template we’re trying to render to use that extension.
Let’s find our template and rename it index.html.leex
.
Then let’s open our template and we have a link to our album show path that uses the @conn
. Let’s go ahead and update it to use our @socket
since @conn
will no longer be available.
Template path: lib/teacher_web/templates/album/index.html.leex
...
<%= link "Show", to: Routes.album_path(@socket, :show, album) %>
...
Then let’s go back to our browser - and perfect our albums are now being rendered with LiveView!
Outsourced Guru
5 years agoApologies, but I found that to be mind-numbingly difficult to follow. The pacing was a bit rushed; there were few times when I could stop and just think about what was happening along the way. If I did want to follow along, I’d probably have to pause/resume the video a few hundred times.
Alekx
5 years agoNo worries, the pace isn’t for everyone, which is why I include the script/code below.
Yesha
5 years agoI think your pacing is great, though a video player with the ‘rewind 10 seconds’ button would be helpful for some of those key moments.
Bangash
5 years agoLooks like this series is the continuation of another lesson or series. What lesson or series is that?
Alekx
5 years agoThe application I am using to implement these features doesn’t have a screencast dedicated to it, but it’s a simple CRUD app that’s essentially the same as covered here. The source is also on GitHub. Hope this helps!