iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0
Modern Web

速成 Phoenix, 2022年最受喜愛框架系列 第 23

{23, LiveView, "用LiveComponent新增"}

  • 分享至 

  • xImage
  •  

再繼續之前處理 CSS 一下

這邊我有寫額外的 css 來正確顯示待會要用到的 modal
專案的 css 都放在 assets/css 資料夾裡
建立一個新的 css 檔案
assets/css/fast_phoenix.css

.modal-background {
    position: fixed;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.4);
    left: 0;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: center;

}

.modal {
    background-color: white;
    width: fit-content;
    height: fit-content;
    min-width: 600px;
    min-height: 300px;
    padding: 2rem;
    border-radius: 0.5rem;
    position: relative;
}

.esc-button {
    width: fit-content;
    height: fit-content;
    position: absolute;
    top: 1rem;
    right: 1rem;
}

有了之後在 assets/css/app.css 前面加上這兩行來 import

/* import 這系列用到的 css 檔案 */
@import "./fast_phoenix.css";

定義 Live Component

上一篇我們使用了 component 來整理重複使用的片段,普通的 component 給他什麼值他就會畫出對應的結果,
我們這次要介紹的 Live Component 則不一樣,他有自己的狀態,自己的動作,有點像是一個小型的 LiveView 頁面。

我們可以做一個叫做 BlogWeb.PostLive.Form 的 Live Component
/lib/blog_web/live/post_live/form.ex

defmodule BlogWeb.PostLive.Form do
  # 這邊跟 live view 不一樣的,他引用的是 live_component
  use BlogWeb, :live_component

  # 跟 live view 用 mount 不一樣,這邊用 update/2
  def update(_assigns, socket) do
    {:ok, socket}
  end

  # 一樣會使用 render 來輸出結果,這邊要注意的是,live_component 外層一定要是一個 dom 元件,如這邊是一個 div
  def render(assigns) do
    ~H"""
    <div>
      <.modal>
        <h1>新增文章</h1>
      </.modal>
    </div>
    """
  end

  def modal(assigns) do
    ~H"""
    <div phx-click="cancel_form" id="modal">
      <div class="modal-background">
        <div class="modal">
          <button phx-click="cancel_form" class="esc-button">x</button>
          <%= render_slot(@inner_block) %>
        </div>
      </div>
    </div>
    """
  end
end

這邊我們來觀察一下這個 modal component

  def modal(assigns) do
    ~H"""
    <div id="modal">
      <div class="modal-background">
        <div class="modal" phx-click-away="cancel_form">
          <button phx-click="cancel_form" class="esc-button">x</button>
          <%= render_slot(@inner_block) %>
        </div>
      </div>
    </div>
    """
  end

這邊 phx-click 是滑鼠按下去執行,phx-click-away 是滑鼠按不是這個元件時(外面的灰背景) 執行, 兩個都是去執行 "cancel_form" 這個關閉這個表格 modal 的事件,
要注意的是,儘管 live component 可以接收自己的事件,預設的事件還是會給上層使用他的 LiveView 頁面來接收。
下一篇我們會使用 target={@myself} 來改由 live component 本身來接收

使用 Live Component

有了 component 之後我們準備要把他加入 之前做的 Live 文章列表
我們可以使用 <.live_component module={模組名稱} id="幫他取一個id" /> 來帶入
但在那之前我們先整理一下我們要達成什麼
我想要有一個新增文章的按鈕,按下去之後顯示我們的準備用來放表格的 Live Component
如果不送出可以按 X 或是 modal 旁邊的陰影來關閉。

要做的事情

  1. 加一個新狀態 :form 到 Index 的 assigns 來決定要不要顯示 新文章表格 live component
  2. 把 Live Component 加進 Index,但是加一個判斷是否使用
  3. 加一個 "新增文章" 按鈕,用來打開表格
  4. 加一個接收新增文章的 handle_event,來把 assigns 裡的 :form 變成 true
  5. 加一個接收關閉 modal 的 handle_event,來把 assigns 裡的 :form 變成 false

編輯 lib/blog_web/live/post_live/index.ex

defmodule BlogWeb.PostLive.Index do
  use BlogWeb, :live_view
  alias Blog.Posts

  def mount(_params, _session, socket) do
    # 這邊再加上 form: false
    # assign 如果是使用兩個變數版本,後面接的是 Map 可收多個 assign
    {:ok, assign(socket, %{posts: Posts.list_posts(), form: false})}
  end
  
  # 取消表格用的 event
  def handle_event("cancel_form", _params, socket) do
    {:noreply, assign(socket, :form, false)}
  end

  # 開啟表格用的 event
  def handle_event("show_form", _params, socket) do
    {:noreply, assign(socket, :form, true)}
  end

  # `<button phx-click="show_form">新增文章</button>` 加上新文章按鈕
  # 
  # 用 if @form 來判斷要不要使用 live component
  # 
  def render(assigns) do
    ~H"""
    <h1>LiveView 文章列表</h1>
    <button phx-click="show_form">新增文章</button>
    <%= if @form do %>
      <.live_component module={BlogWeb.PostLive.Form} id="modal" />
    <% end %>

    <table>
      <.table_head />
      <.table_body>
        <%= for post <- @posts do %>
          <.post_row post={post} />
        <% end %>
      </.table_body>
    </table>
    """
  end
  # 下面還有 thead 等等 component 這次不會改到
end

開啟前

https://ithelp.ithome.com.tw/upload/images/20220927/201410547unoca5oEo.png

開啟後

https://ithelp.ithome.com.tw/upload/images/20220927/20141054EddD2MVcml.png


上一篇
{22, LiveView, "列表與Component"}
下一篇
{24, LiveView, "LiveView裡的表格"}
系列文
速成 Phoenix, 2022年最受喜愛框架30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言