iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
Modern Web

Phoenix 1.7 完全教學系列 第 12

12 Index 頁面

  • 分享至 

  • xImage
  •  

前面提到瀏覽器送來的要求經過 router 比對之後會送到設定的 controller,接著 controller 從 context 取得資料,並且把資料填入 html template,最後回傳 html 頁面。

我們一步一步的從 controller 開始,把這些零件建立起來。

先使用 mix phx.server (或 iex -S mix phx.server) 開啟伺服器,並在網址輸入我們前一篇設定好的 note 列表畫面網址 http://localhost:4000/notes

https://ithelp.ithome.com.tw/upload/images/20230927/20141054e7Mlqs1IzC.png

我們馬上看到,因為我們只有設定好 router,卻沒有建立我們在上面寫的 Controller module,所以出現錯誤訊息:

function GratitudeWeb.NoteController.init/1 is undefined (module GratitudeWeb.NoteController is not available)

module GratitudeWeb.NoteController is not available
他找不到這個 module,因為我們還沒有建立他。

建立 Controller

建立一個檔案 lib/gratitude_web/controllers/note_controller.ex,並且加入以下程式碼:

defmodule GratitudeWeb.NoteController do
  use GratitudeWeb, :controller
end

這裡我們使用 use GratitudeWeb, :controller 來引入 Phoenix 的 controller 功能。

(如果有興趣的話可以研究一下 use 與 GratitudeWeb 裡面的 controller 是怎麼實作的,但是目前可以暫時把這段當成 Controller 就好。)

現在我們再次開啟網頁,會看到錯誤訊息變成:

https://ithelp.ithome.com.tw/upload/images/20230927/20141054fCB3BGjEgg.png

function GratitudeWeb.NoteController.index/2 is undefined or private

記得我們在 router 定義的時候是寫(用 resources 替代也是一樣)

get "/notes", NoteController, :index

Phoenix 的 Router 非常直覺,依照上面設定,就會去找 NoteController 裡面的 index 函式。

(題外話:不管是 Elixir 或 Phoenix,會希望寫的明顯直覺一些,盡量不要有隱藏的邏輯,所以這邊不管我們要接的 module 放在哪叫什麼都沒關係,目前看起來雖然有點攏長,感覺需要寫很多,不過這點在實際專案東西多了之後,會發現這樣寫比較好找,也方便修改。)

我們在 NoteController 裡面加入 index 函式:

defmodule GratitudeWeb.NoteController do
  use GratitudeWeb, :controller

  def index(conn, params) do
  end
end

從 router 呼叫來 controller 的時候,會傳入兩個參數,第一個是 conn,第二個是 params
conn 代表目前的連線,params 則是這次要求帶來的參數。

Phoenix.Controller module 裡面,有一系列可以在 controller 裡面使用的函式,我們先試試看 html 這一個。

def index(conn, params) do
  html(conn, "Hello World")
end

現在我們再次開啟網頁,我們可以看到我們直接印出來的文字

https://ithelp.ithome.com.tw/upload/images/20230927/20141054XlLJKjny01.png

雖然是有東西了,但是我們會希望回傳的是一個完整的 html 頁面,因此我們需要一個 html template,然後在這邊呼叫他。

建立 html template

目前的 note controller 位於 controllers 資料夾底下
在 Phoenix 1.7 之後,note controller 的 html template module 一樣放在 controllers 資料夾底下,名稱則是 note_html.ex

我們建立 lib/gratitude_web/controllers/note_html.ex,並且加入以下程式碼:

defmodule GratitudeWeb.NoteHTML do
  use GratitudeWeb, :html

  embed_templates "note_html/*"
end

我們在這邊使用 use GratitudeWeb, :html 來引入 Phoenix 的 html 功能。

(與 controller 一樣,如果有興趣的話可以研究一下 use 與 GratitudeWeb 裡面的 html,但現在可以先忽略。)

embed_templates "note_html/*" 告訴 Phoenix 我們要把 template 放在 note_html 資料夾裡面。一樣,雖然可以自己定義,但是目前我們先依照 Phoenix 預設的規則就可以了。

在 controller 裡面建立 note_html 資料夾,並在裡面新增一個這一次要使用的 template index.html.heex

加入以下 html:

<h1>所有的感激筆記</h1>
稍後會在這邊加入筆記列表

我們再回到 note controller 使用 render 來呼叫這個 template:

def index(conn, params) do
  render(conn, :index)
end

這個時候再打開同一個頁面,我們就可以看到我們剛剛寫的 html template 了。

https://ithelp.ithome.com.tw/upload/images/20230927/20141054GbYPzNxAcj.png

列出所有的筆記

我們剛剛從 router 到 controller 到 template 並且成功的顯示出一個 html 頁面,但其實少了從 context 拿到目前所有筆記的部分。

在我們已經先建立好 context 的情況下,我們可以直接呼叫 Gratitude.Notes.list_notes() 來取得所有的筆記。因為我們會在這邊使用多次 Gratitude.Notes 所以可以使用 alias 讓我們不用一直打這麼長的名稱。

lib/gratitude_web/controllers/note_controller.ex 修改為:

defmodule GratitudeWeb.NoteController do
  use GratitudeWeb, :controller
  alias Gratitude.Notes

  def index(conn, params) do
    notes = Notes.list_notes()
    render(conn, :index, notes: notes)
  end
end

再使用 Notes.list_notes() 後,我們可以藉由 render 把他帶到 template 裡面。

lib/gratitude_web/templates/note_html/index.html.heex 修改為:

<h1>所有的感激筆記</h1>
<%= for note <- @notes do %>
  <p><%= note.content %></p>
<% end %>

畫面變成:

https://ithelp.ithome.com.tw/upload/images/20230927/2014105475fp3NWQ1l.png


上一篇
11 Router
下一篇
13 Index 頁面測試
系列文
Phoenix 1.7 完全教學30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言