Phoenix: injecting into assigns for passing to another template

In the post/show template I have:

<%= for comment <- @comments do %>
     if (condition) do
        # pass comment to _scripts.html 
     end
end

The objective is that in the _scripts.html, I need the comment available. (_scripts.html has javascript associated with the template)

By default, if I don’t do anything then the render line in post controller render(conn, "show.html", post: post, comments: comments) gives _scripts.html the Available assigns: [:conn, :post, :comments, ...].

So therefore to inject comment into the available assigns I do:

if (condition) do
    # pass comment to _scripts.html 
    <%= render "_scripts.html", Map.put(@conn.assigns, :comment, comment) %>
end

which gives available assigns: [:comment, :post, :comments, ...] but the conn goes missing.

So, instead I tried doing:

if (condition) do
    # pass comment to _scripts.html 
    <%= render "_scripts.html", Map.merge(@conn.assigns, %{comment: comment, conn: @conn}) %>
end

but then conn is available while comment goes missing, as in: assign @comment not available in eex template. Available assigns: [:conn, :post, :comments, ...]

Any help on this will be appreciated.

I think you are confusing conn.assigns with template assigns. Try simply:

if (condition) do
    <%= render "_scripts.html", conn: @conn, comment: comment) %>
end
1 Like

Hey @grych, I tried your solution but it didnt work, I still get assign @comment not available in eex template.

Here on SO I found, a community member explains the difference between assigns and conn.assigns.

Please share your exact code, you must have done some other mistake there. @comment should be available in the "_script.html" when you pass it to render/2

2 Likes

You’re right but I think there’s a typo…try:

if (condition) do
    <%= render "_scripts.html", conn: @conn, comment: @comment) %>
end
1 Like

Nope, that won’t work. Please take a look at the OP, there is a comprehension missing parts of the implementation, while later on that call to render/2 is revealed as beeing the implementation.

1 Like

As I understood from the code sample at the first post, comment is a local variable, not an assign.

2 Likes

Yes, right. I didn’t see the code sample carefully.

Hi @grych, I think you are wondering if the condition evaluates to true, which dictates if the comment will be passed to _scripts.html. The condition does not change, and the line <%= render "_scripts.html", Map.put(@conn.assigns, :comment, comment) %> does give @comment to _scripts.html but @conn goes missing.

Any ways I realized two things, firstly while testing around other methods like doing:
<%= render "_scripts.html", conn: @conn, post: @post, comment: comment %>

that it works when I do the above line, but then the _scripts.html file complains @current_user not available (while conn, post and comment are available).

Then to resolve that I do:
<%= render "_scripts.html", conn: @conn, post: @post, comment: comment, current_user: @current_user %>
and it says @comment not available.

The second thing I realized is that even if comment were available from the for loop in the post/show template to the _scripts.html its only 1 comment (the first or the last comment) available at page load, since javascript is loaded.

So what I was trying to eventually do in the _scripts.html file, that is to save the reply to a comment as a draft in localStorage, in case the user navigates away accidentally from the individual post show page, would probably not work with that implementation.

$("#reply_<%= @comment.id %>").keyup(function() {
  var reply = { 'id': <%= @comment.id %>, 'draft': $("#reply_<%= @comment.id %>").val()};
  localStorage.setItem("reply_draft_<%= @comment.id %>", JSON.stringify(reply));
});

Uhhh what? Why are you taking the plug’s assigns and passing it as the view assigns, those are two different set of assigns, and thus of course @conn would go missing. That render call is definitely wrong, it should be more like:

<%= render "_scripts.html", conn: @conn, comment: comment %>

(Well you could pass in @assigns, @assigns != @conn.assign for note, @assigns is what was actually passed into the template.)

Correct, you have to pass in everything to a render call explicitly.

@comment should most definitely be accessible within "_script.html" with that render call.

Seems like it should work.

Hey @grych, @PJextra, @NobbZ and @OvermindDL1 , thanks for all you guys input, doing <%= render "_scripts.html", conn: @conn, post: @post, comment: comment %> finally worked (duh…what a hard and complicated solution to finally arrive at…eh). I just tackled the current_user problem in an another way. @OvermindDL1 thanks man for explaining it and getting the head think straight.

1 Like

<%= render "_game_app_nav.html", assigns %>

2 Likes