DaAnalyst

DaAnalyst

Passing argument to LV template without assigns

The UC: I have two structures, each with its own lifecycle. The structure A is the larger one and is always fully rebuilt for each LV rendering cycle. The structure B is the configuration of the structure A, is small in size and is intended to be updated (not fully rebuilt) in each LV rendering cycle, with full reset on refresh. The structure B is a perfect candidate for the socket.assigns while the structure A is not for I don’t need it assigned.

However, both the rebuild of structure A instance and the updating of structure B instance take place within a single algo run. The problem that arises here is that I cannot call this algorithm from within the template as I don’t think (correct me if I am wrong) that there is a way to assign the updated structure B instance from the template. While if I run the algo from my LV module (in the handle_info function, for example) the only choice I have then is to assign both instances to socket.assigns for I don’t know how else I can make the structure A instance visible to the template.

In short, is there a point in the LiveView framework where I could compute the instances of both structures and assign just one of them, while making the other one also accessible to the template code, but without assigning it to the socket.assigns?

Marked As Solved

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Are you constructing it in the def render callback?

Do note that if live view can determine that the assigns have not changed it will not re-render that part of the page, nor will it push updates over the wire.

Some of this feels like premature optimization.

Assigns are the only way to get a value in the template, you do need it to be assigned. I would start with the simple assign based solution, and then measure memory usage and benchmark various aspects of your live view. If you have memory savings you want to achieve, temporary assigns are the solution. If it isn’t clear how to apply those to your situation, that’s the line of questioning that is likely to be most productive.

Also Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

The absence of code examples has me a little bit lost here. Let’s make this slightly more concrete. You have @foo, and there is some transform(@foo) that produces a bunch of data you actually want to render, but transform/1 is somewhat expensive yes? So you want to make sure that it only actually gets called if @foo changes, and not simply because some other value @bar changes?

Eg:

# index.html.leex
<html>
<body>
<p><%= @bar %></p>
<p><%= transform(@foo) %></p>
</body>
</html>

If @bar changes a lot, but @foo changes very rarely, you don’t want to re-run transform/1 every time @bar changes.

The first thing I’d do is make sure that this problem actually happens, live view is getting new optimizations all the time, I’d put some kind of debug logging inside transform/1 and validate that it is being in fact called every time @bar changes.

If it is, try moving transform(@foo) into a partial (make sure the partial is .leex):

# _foo.html.leex
<p><%= transform(@foo) %></p>

# index.html.leex
<html>
<body>
<p><%= @bar %></p>
<p><%= render(@live_view_module, "_foo.html.leex", foo: @foo) %></p>
</body>
</html>

This allows optimizations around rendering partials to take place. If that still isn’t working then that sounds like a bug, those optimizations have been in for a while. If you have a BUNCH of state you want to manage around @foo a component may help, but this should help.

You can create some |> assign(:baz, transform(assigns.foo)), and then use @baz in the template, which helps avoid having transform/1 called unnecessarily, but at the expense of having to keep the result of transform/1 in memory. If this is an issue we can explore the temporary assigns route, but without a good illustration of the issue it’s hard to talk about specific tactics. It depends a lot on exactly how expensive transform/1 actually is.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

To some extent this is just fundamentally at odds with the live view paradigm. What you’re suggesting is basically a side cause, a value that is not treated as an input to the render function, but rather a thing that simply happens to be available. This is fundamentally at odds with how LiveView (and similar UI frameworks) treat rendering, it is a pure relation between a set of inputs and an outputed template. This is, for example, why calling DateTime.utc_now() in your template or in a view helper will not work correctly, and why you should instead do |> assign(:now, DateTime.utc_now()) and use @now.

However! Perhaps the issue here is that you’re operating as if the socket assigns are the only way to maintain state on the socket. Maybe using the private key of the socket will help, so that you can hold on to a value and then only at some later time actually add it to the assigns to be rendered. You could place the value you get from handle_info in the socket private key, and then you can have some other event move the value from private to assigns when you want it to effect the view.

DaAnalyst

DaAnalyst

Yes, that is precisely what I am doing now. I was just asking if there was a way not to. And transform/1 is expensive enough for not having to invoke it more than once per cycle.

But, now that you’ve mentioned this private key thing, I’m considering changing the design a bit so that the result of transform/1 keeps gettting assigned but its input data does not (but stored as private instead). Need to check of whether that’s gonna be possible. Thanks!

Where Next?

Popular in Discussions Top

Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
jeramyRR
This is an interesting article to read. Elixir’s performance, like usual, is excellent. However, it seems like the high CPU usage is co...
New
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
mmport80
I have put far too much effort into Dialyzer over the last year or so - and basically - I doubt it’s worth the effort. It’s not as easy ...
New
chuck
Let me start by stating an assumption: Phoenix is a great approach to building REST APIs. There are many reasons for this, but I will ass...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31142 143
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
acrolink
How does the two languages compare when it comes to server side application development? Any experiences or ideas? Thank you.
New
pdgonzalez872
If this has been asked here before, please point me to where it was asked as I didn’t find it when I searched the forum. Maybe a mailing ...
New

Other popular topics Top

Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41539 114
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
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
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
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

We're in Beta

About us Mission Statement