loretoparisi
loretoparisi

Reputation: 16271

Call a view with render in Phoenix Elixir

In my Phoenix/Elixir boilerplate web app I have the typical structure described here, where the simple HelloController uses a HelloView component to render the templates in the hello/ folder. This works ok. Now let's say I want to add the snake_view.ex View component here. This View depends on Phoenix LiveView and acts slightly different than other ordinary views, that render templates, since it has a render method in it among the other functions:

defmodule HelloWeb.SnakeView do
  use Phoenix.LiveView
   # ..
   def render(%{game_state: :over} = assigns) do
   # ..

Now, after adding the LiveView dependency, I have added a route in router.ex

get "/snake", SnakeController, :index

But now I do not know how to reference the SnakeView from this new SnakeController:

defmodule HelloWeb.SnakeController do
  use HelloWeb, :controller

  def index(conn, _params) do
    render(conn)
  end
end

The error I get when heading to http://localhost:4000/snake is

function HelloWeb.SnakeView.render/2 is undefined or private

so it seems that from the router the SnakeController has been invoked, and the SnakeView as well, but something is wrong.

[UPDATE]

I have realized that there were a lot of things I was missing to do before make it working the Phoenix LiveView within the PhoenixFramework WebApp:

  1. Endpoint endpoint.ex. You need to add a

    socket "/live", Phoenix.LiveView.Socket
    
  2. Router router.ex. Add a route to the LiveView via the PageController:

    get "/snake", PageController, :snake
    
  3. In the PageController add a def for the snake function:

       def snake(conn, _) do
           conn
           |> put_layout(:game)
           |> LiveView.Controller.live_render(HelloWeb.SnakeLive, session: %{})
         end
    
  4. WebApp your_app_web.ex. Add in view def the

    import Phoenix.LiveView, only: [live_render: 2, live_render: 3]
    
  5. Config in configs.exs. Add a LiveView salt token:

    live_view: [
        signing_salt: "YOUR_LIVEVIEW_TOKEN"
     ]
    
  6. Add a live folder in your your_app_web web app folder. Put your LiveView view there.

  7. Add the WebSocket connection in the main app.js file:

        import {LiveSocket, debug} from "phoenix_live_view"
        let liveSocket = new LiveSocket("/live")
        liveSocket.connect()
    
  8. Added css resources: live_view.css, snake.css, imported in app.css the new css:

        @import "./phoenix.css";
        @import "./live_view.css";
        @import "./snake.css";
    

The resulting WebApp structure should now be:

├── assets
│   ├── css
│   │   ├── app.css
│   │   ├── live_view.css
│   │   ├── phoenix.css
│   │   └── snake.css
│   ├── js
│   │   ├── app.js
│   │   └── socket.js
├── config
│   ├── config.exs
├── lib
│   ├── hello
│   │   └── application.ex
│   ├── hello.ex
│   ├── hello_web
│   │   ├── channels
│   │   ├── controllers
│   │   ├── endpoint.ex
│   │   ├── gettext.ex
│   │   ├── live
│   │   ├── router.ex
│   │   ├── templates
│   │   └── views
│   └── hello_web.ex

At this stage, when pointing the browser to http://localhost:4000/snake I get the LiveView partially working:

enter image description here

Please check the full code here to investigate this issue.

Upvotes: 1

Views: 2523

Answers (1)

GenKali
GenKali

Reputation: 600

At the bottom of this page - https://github.com/phoenixframework/phoenix_live_view - there's at least one step that I'm not seeing in your code.

// assets/js/app.js
import LiveSocket from "phoenix_live_view"

let liveSocket = new LiveSocket("/live")
liveSocket.connect()

Perhaps add that and confirm that you have the rest of the steps covered as well. Hopefully that works :)

Upvotes: 2

Related Questions