Best practice to pass data from Phoenix to Javascr

2019-06-25 13:43发布

I see 3 ways of doing this.

  1. Using <%= %> inside <script> in *.html.eex
  2. Use channels to pass data to Javascript
  3. Build a json api

#1 seems the easiest but I couldn't find or think of a good way to do it yet.

Note: real-time update is not my requirement.

4条回答
小情绪 Triste *
2楼-- · 2019-06-25 14:16

I would never use a <script></script> for that, in my projects I have this pattern:

<!-- Layout -->
<div id="config"
  data-environment="..."
></div>

I always provide the current environment in the master layout, I have a config.jsfile with the right data for the right environment.

When I need to pass some data to my javascript I do something like that in my view:

<div id="app"
  data-users="..."
  data-zombies="..."
  ...
></div>

If you abstract that with some helpers (elixir side) you can do:

<%= App.Helpers.make_html(:app, [users: @users, zombies: @zombies]) %>

In the javascript side, when I load the page I just extract the data-attributes and set them in a variable options for the current controller:

class ZombieController extends Controller

  setup: ->

    console.log(@options) # I have all the data there.

    # I can do 
    zombies = @options.zombies

Well, it's just an example and you should adapt that for your current project. The key is to abstract.

Hope it helps :)

查看更多
我只想做你的唯一
3楼-- · 2019-06-25 14:27

Best Practice depends on your front end.

If you are basically serving HTML with dribbles of javascript. Inject data into the html or via script tag

If you are building a react / angular / front end, then consider using an API and/or Channels.

In general, if it's a significant web app that will require data to be manipulated via javascript, I'd go the API/Channel route.

查看更多
贪生不怕死
4楼-- · 2019-06-25 14:33

(2) is not a good idea if you don't want real time updates. (3) may be too unnecessarily complicated if you don't want to load the data using AJAX. You should use (1) if you just need some data to be accessible from JS and don't want to change it without a whole page reload.

Since valid JSON is also valid JS, you can just use Poison.encode!(). If your data is in @posts, you can do this in *.html.eex:

<script>
  var POSTS = <%= Poison.encode!(@posts) %>;
</script>

and then load other JS after this and access the posts using the global POSTS variable. (You might want to namespace it into something like App.posts = ...:

<script>
  var App = window.App || {};
  App.posts = <%= Poison.encode!(@posts) %>;
</script>

Make sure @posts only contains data that can be converted to JSON (no tuples) and only has the fields that the user is allowed to see.

查看更多
叛逆
5楼-- · 2019-06-25 14:38

Also you can use hex PhoenixGon it uses the first way for passing Phoenix variables to Javascript. It takes all variables from controller and Mix.env and generate <script> tag with rendered JSON and methods for accessing to this data. See other answeres here. It's like:

def index(conn, _params) do      
  conn = put_gon(conn, [users: Repo.all(Users), zompies: Repo.all(Zombies)])
  render(conn, "index.html", current_user: get_session(conn, :current_user))
end

And in js Code:

window.Gon.getAsset('users') #=> [user list]
windoe.Gon.isDev() # => true

And you don't need create @vars and keep it clear.

And for zommbies.coffee:

class ZombieController extends Controller

  setup: ->

    zombies = window.Gon.getAsset('zombies')
查看更多
登录 后发表回答