tj0

tj0

Phoenix 1.6 to 1.7 upgrade with optional phoenix_view removal

I’ve been following the steps here for the upgrade from 1.6 to 1.7 and it has gone relatively smoothly all the way till the phoenix_view to phoenix_component switch. verified_routes are quite nifty.

In the past, I’ve found the liveview upgrades / breaking changes to be extremely valuable. I’m not quite sure about the phoenix changes though, but since I’m not sure phoenix_view will be deprecated in the future, I’m willing to put in the legwork to do the migration.

To summarize for those considering the upgrade and all the layout changes:

  • there is no views directory. Not sure where any functions are supposed to go that were in views.
  • liveview templates are colocated in the liveview directory or embedded
  • livecomponent templates are…I’m not sure where.

The two main issues I’m having are

  1. The templates for my LiveViews and LiveComponents are from 200-600 lines. These are far too large to embed into the render/1 function and I’m not sure how to pass on the assigns to the template.

Original

import AppWeb.ChartView
def render(assigns) do
  AppWeb.ChartView.render("show.html", assigns)
end

New one where it’s not indicated how to pass the assigns into the

  use AppWeb, :live_view
  embed_templates "../templates/chart/*"
  def render(assigns) do
      # does not pass the assigns into the show and if they are passed as assigns={assigns} will need a template re-write
        ~H"""
        <.show />
        """
  end

I was hoping for something like the below code, but I cannot call render/2 or Phoenix.LiveView.render/2 because “(module Phoenix.Liveview is not available)”


def render(assigns) do
        ~H"""
        <%= Phoenix.LiveView.render "show.html", assigns %>
        """
end
  1. I’ve put rendering specific functions into the views. App.ChartView has functions for making viewable dates, converting decimals to fractions, capitalization, etc.

I like the idea of getting rid of the views directory as it seemed like mostly boilerplate. However, I can’t figure out how to do an easy migration of the templates to use phoenix_component instead of phoenix_views.

I’m not understanding how to replace the render functions in a way that doesn’t require massive changes to the templates or how to pass in the helper functions for the view itself. What am I missing?

Marked As Solved

tj0

tj0

After a bit of fiddling with the syntax, the following seems to work (thanks @codeanpeace , your suggestion was pretty close).

  use AppWeb, :live_component

  import AppWeb.ChartView # for all the rendering helper functions
  embed_templates "../templates/chart/*"

  def render(assigns) do
    ~H"""
    <div>
    <%= show(assigns) %>
    </div>
    """
  end

The existing template has a root div element, however, without wrapping the ~H in a div, we " Stateful components must have a single static HTML tag at the root".

Still not sure how to do conditional rendering yet.

I’m relieved as I’m not sure how risky this upgrade is to be honest. Might have a lot of little gotchas and needs extensive testing.

Also Liked

josevalim

josevalim

Creator of Elixir

FWIW, Phoenix View is not deprecated and we are committed to keeping it working in the long term. I will make the docs clearer. :slight_smile:

codeanpeace

codeanpeace

Maybe something like:
<%= ChartView.show(assigns) %>

From Migrating to Phoenix.Component | Phoenix.View:

Remove def view and also remove the import Phoenix.View from def html in your lib/my_app_web.ex module. When doing so, compilation may fail if you are using certain functions:

  • Replace render/3 with a function component. For instance, render(OtherView, "_form.html", changeset: @changeset, user: @user) can now be called as <OtherView.form changeset={@changeset} user={@user} />. If passing all assigns, render(OtherView, "_form.html", assigns) becomes <%= OtherView._form(assigns) %>.
  • If you are using Phoenix.View for APIs, you can remove Phoenix.View altogether. Instead of def render("index.html", assigns), use def users(assigns). Instead of def render("show.html", assigns), do def user(assigns). Instead render_one/render_many, call the users/1 and user/1 functions directly.

And from Compartmentalize state, markup, and events in LiveView | Phoenix.LiveView:

However, sometimes you need to compartmentalize or reuse more than markup. Perhaps you want to move part of the state or part of the events in your LiveView to a separate module. For these cases, LiveView provides Phoenix.LiveComponent, which are rendered using live_component/1:

<.live_component module={UserComponent} id={user.id} user={user} />
codeanpeace

codeanpeace

Ahh nice! Since you import AppWeb.ChartView, it makes sense that you can just use <%= show(assigns) %>.

Yup, that’s the primary issue. A secondary issue would be to place logic in the appropriate callbacks to optimize for efficient code execution.

The way I currently think about it is that the render callback is invoked the most frequently so anything that doesn’t need to be in render should be moved out of render. So something that would be just fine in mount and render should be in mount as it’s invoked less often. For example, if assigns.user doesn’t change after mount, it would make sense to move the assign_new logic from render to mount. If it does change due to push_patch, then handle_params would be a good spot for it.

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call t...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54120 245
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement