Phoenix Framework:在 JSON 响应中发送呈现的模板

Phoenix Framework: Send rendered template in JSON response

我在 top_navigation.html 中有一个用于我的应用程序顶部导航的模板,其中包含 "Sign in"、"Sign up",并且在登录后,"Sign out" links.

<%= if logged_in?(@conn) do %>
  <li><%= link "Sign out", to: session_path(@conn, :delete), method: :delete %></li>
<% else %>
  <li><a href="#" class="js-register" data-toggle="modal" data-target=".js-register-modal">Sign up</a></li>
  <li><a href="#" class="js-login"    data-toggle="modal" data-target=".js-login-modal"   >Sign in</a></li>
<% end %>

我通过 AJAX 登录用户,但是一旦他们登录,我想用新呈现的模板(显示 "Sign out" link), 在登录响应中传递回客户端。

有没有办法将呈现的模板作为 JSON 响应的一部分发送?

大致如下:

defmodule MyApp.SessionController do
  use MyApp.Web, :controller

  def create(conn, %{"user" => user_params}) do
    case MyApp.Session.login(user_params, MyApp.Repo) do
      {:ok, user} ->
        conn
        |> put_session(:current_user, user.id)
        |> json %{ top_navigation: render("top_navigation.html") }
                                   # ^^^^ this doesn't work ^^^^
      :error ->
        conn
        |> put_status(404)
        |> json %{ message: "Unable to sign in." }
    end
  end

  def delete(conn, _) do
    conn
    |> delete_session(:current_user)
    |> put_flash(:info, "Signed out.")
    |> redirect(to: "/")
  end
end

和 Javascript:

$(".js-login").on("click", e => {
  e.preventDefault()
  $(".js-login-alert").hide()
})
$("#login").on("submit", e => {
  e.preventDefault()

  let form = $("#login")
  let data = { _csrf_token: $( 'input[name="_csrf_token"]' ).val(), 
               user:        { email:    form.find('input[name="email"]'   ).val(), 
                              password: form.find('input[name="password"]').val() } }

  $.ajax({
    type: "POST",
    url: "/login",
    data: data,
    success: e => {
      $(".js-top-navigation").html(e.responseJSON["top_navigation"])
      // ^^^^^^^^^^^^^^ This is where we swap it out ^^^^^^^^^^^^^^^
      $(".js-login-modal").modal("toggle")
    },
    error: e => {
      let alert = $(".js-login-alert")
      alert.text(e.responseJSON["message"])
      alert.show()
    }
  })
})

提前致谢!

没错! Phoenix 模板只是它们视图模块上的函数。所以你可以通过调用一个函数来渲染一个模板:

|> json(%{nav: Phoenix.View.render_to_string(MyView, "nav.html", conn: conn)})