0

I defined a helper function in the view:

def usernames(id) do
  post = Repo.get(Post, id) |> Repo.preload(comments: :user)
  usernames = for comment <- post.comments do
     comment.user.username
  end
end

Then in the javascript file I do:

$('#comment').doThis({
   data: "<%= escape_javascript( MyApp.ApplicationHelpers.usernames(@post.id) ) %>"
});

The above does not work. Of course I need to be able to pass in the @post.id, but even by hardcoding a post id like MyApp.ApplicationHelpers.usernames(5), doesn't work.

Basically I am trying to do the Rails equivalent of:

@usernames = User.pluck(:username)

Then in the js.erb would have been:

data = <% @usernames %>
$('#comment').doThis({'data': data});

If someone can help out in how to achieve this...

Update: (to provide additional info) I put the javascript code in posts.js as following this stackoverflow answer. Other javascript code in that file executes as needed.

6
  • Could you specify where is your javascript file and the extension of it? Because I think you are mixing .eex with .js which is not possible afaik. Commented May 24, 2017 at 0:11
  • Hey @emancu I added information in the update to the question, as you asked. Commented May 24, 2017 at 0:18
  • Possible duplicate of How to execute elixir code in a js file? Commented May 24, 2017 at 5:27
  • @PatrickOscity Thanks so much for stopping by at the question. Your answer on the linked question (basically hard coding it in as a data attribute) was very helpful. It worked precisely as needed in a scenario whereby I needed the post url and post title in the javascript file. But for this one, though your solution would have worked, it was not feasible to hard code all the users, especially since if the user list grows. Commented May 24, 2017 at 5:42
  • 1
    @codingbear yeah you're right, hard coding is not an option here but a global window object, data attributes or separate JSON endpoint would be feasible. If you're concerned with the size of the data attribute - in HTML 5 there is no size limit on attributes so you should be fine. Just wanted to let you know that embedding Elixir code in static assets is not really an option with Phoenix and which solutions exist to handle such situations. Commented May 24, 2017 at 7:31

1 Answer 1

2

Well @codibgbear the thing is, phoenix will take that as a regular js file so it won't compile the code, which means that your EEX syntax won't work.

What you can do is to define a partial next to your template called _scripts.html.eex and add the following code

<script>
  $('#comment').doThis({
    data: "<%= escape_javascript(usernames(@post.id)) %>"
  });
</script>

Then on your template, make sure you are rendering this partial.

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

Actually, you should check your templates/layout/app.html.eex file and see if there is a line already to render this file magically ;)

The line should look like:

<%= render_existing view_module(@conn), "_scripts.html", assigns %>

And since you defined the usernames/1 function in the view, you don't need to use the entire module name, so I think this should work.

Good luck!

Sign up to request clarification or add additional context in comments.

5 Comments

Hey @emancu, Thanks for giving an answer. I am going to try it out.
Hey @emancu, I added your suggested code, and as I was doing it, your logic made sense. I added this line as you suggested <%= render_existing view_module(@conn), "_scripts.html", conn: @conn %> to templates/layout/app.html.eex, but I get the error that assign @post not available in eex template. How do I pass on the @post to the available assigns.
Well. You are actually sending the @conn so you should be able to get the post from there. Something like '@conn.assigns.post' if you assigned it in the controller.
it ended up working out like this: <%= render_existing view_module(@conn), "_scripts.html", assigns %>. if you amend it to that I could mark it as correct. I am gonna vote it up at the moment.
Thanks so much @emancu for taking the time and writing up the answer as well as following up on the comments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.