Phoenix LiveView를 사용하여 간단한 캘린더 클론 구축(4부분)

64448 단어 liveviewelixirphoenix
이 시리즈의 마지막 부분에서 프로그램의 초기 페이지를 실현했습니다. 모든 사용 가능한 이벤트 유형을 보여 줍니다. 방문자가 하나를 선택한 다음 빈 페이지로 넘어갑니다.이를 위해 라이브 세션 및 기능 구성 요소와 같은 LiveView 기능을 활용했습니다.이 부분에서 우리는 먼저 빈 CalendlexWeb.EventTypeLive 라이브뷰를 둘러싼 모든 논리를 실현할 것이다.우리는 달력을 보여 방문객들이 달을 훑어보고 날짜를 선택하도록 할 것이다.우리 시작합시다!

초기 이벤트 유형 페이지 표시


먼저 CalendlexWeb.EventTypeLive 모듈을 수정하여 해당 이벤트 유형을 마운트 리셋에 로드합니다.
# ./lib/calendlex_web/live/event_type_live.ex

defmodule CalendlexWeb.EventTypeLive do
  use CalendlexWeb, :live_view

  alias CalendlexWeb.Components.EventType

  def mount(%{"event_type_slug" => slug}, _session, socket) do
    case Calendlex.get_event_type_by_slug(slug) do
      {:ok, event_type} ->
        socket =
          socket
          |> assign(event_type: event_type)
          |> assign(page_title: event_type.name)

        {:ok, socket}

      {:error, :not_found} ->
        {:ok, socket, layout: {CalendlexWeb.LayoutView, "not_found.html"}}
    end
  end
end
수신된 매개 변수에서 이벤트 형식 slug를 가져옵니다. Calendlex.get_event_type_by_slug/1 함수를 호출합니다.이벤트 유형이 있으면 소켓에 할당하고 페이지 제목을 설정합니다.반대로 일반적인 오류 페이지가 나타납니다.우선 Happy path를 살펴보고 Calendlex.get_event_type_by_slug/1의 기능을 살펴보겠습니다.
# ./lib/calendlex.ex

defmodule Calendlex
  # ...

  defdelegate get_event_type_by_slug(slug),
    to: Calendlex.EventType.Repo,
    as: :get_by_slug
end
그것은 그것을 Calendlex.EventType.Repo.get_by_slug/1 함수에 호출했다.다음 사항을 보완해 보겠습니다.
# ./lib/calendlex/event_type/repo.ex

defmodule Calendlex.EventType.Repo do
  alias Calendlex.{EventType, Repo}

  # ...

  def get_by_slug(slug) do
    case Repo.get_by(EventType, slug: slug) do
      nil ->
        {:error, :not_found}

      event_type ->
        {:ok, event_type}
    end
  end
end
만약 우리가 Phoenix 서버를 시작하고 http://localhost:4000/15-minute-meeting을 방문한다면, 우리는 빈 페이지를 정확하게 볼 수 있을 것이다.이제 오류 경로를 처리하고 not_found 레이아웃 템플릿을 만듭니다.
# ./lib/calendlex_web/templates/layout/not_found.html.heex

<main role="main" class="py-32 mx-auto">
  <div class="w-2/5 mx-auto">
    <div class="px-6 py-12 mb-2 text-center bg-white border border-gray-200 shadow-md rounded-md gap-x-2">
      <header class="mb-8 text-lg font-bold text-gray-900">
        <h2><%= @owner.name %></h2>
        <p>This Calendlex URL is not valid.</p>
      </header>
      <p>If you are the owner of this account, you can log in to find out more.</p>
    </div>
  </div>
</main>
잘못된 URL(예: http://localhost:4000/invalid-event-type)에 액세스한 경우 다음을 확인해야 합니다.

위대하다CalendlexWeb.EventTypeLive 템플릿 파일을 편집하고 초기 내용을 추가합니다.
# ./lib/calendlex_web/live/event_type_live.html.heex

<div class="w-3/5 mx-auto">
  <div class="flex flex-auto p-6 mb-2 bg-white border border-gray-200 shadow-md rounded-md gap-x-2">
    <div class="flex-1">
      <div class="mb-4">
        <%= live_redirect to: Routes.live_path(@socket, CalendlexWeb.PageLive) do %>
          <div class="flex items-center justify-center inline-block text-xl text-blue-500 border rounded-full w-9 h-9">
            <i class="fas fa-arrow-left"></i>
          </div>
        <% end %>
      </div>
      <h4 class="text-gray-500">Bigardone</h4>
      <h1 class="my-3 text-xl text-black"><%= @event_type.name %></h1>
      <div class="flex flex-row items-center mb-2 text-gray-500 gap-2">
        <div class="text-gray-300">
          <i class="far fa-clock"></i>
        </div>
        <%= @event_type.duration %> min
      </div>
    </div>
    <div class="px-8 border-l border-gray-100">
      <header class="mb-8">
          <h3 class="text-lg font-semibold text-gray-900">Select a date & time</h3>
      </header>
    </div>
  </div>
</div>
브라우저가 페이지를 새로 고치면 다음과 같은 내용이 표시됩니다.

달력 렌더링


처음 배치가 끝난 후 달력을 만들기 시작합시다.날짜와 시간을 처리하고 포맷할 것이기 때문에 Timex을 사용하도록 하겠습니다. 이것은 제가 이런 상황에 자주 사용하는 라이브러리입니다.설치하려면 mix 파일의 종속 항목에 추가하고 해당하는 mix deps.get 명령을 실행해야 합니다.
# ./mix.exs

defmodule Calendlex.MixProject do
  use Mix.Project

  # ...

  defp deps do
    [
      # ...
      {:timex, "~> 3.7"}
    ]
  end

  # ...
end
계속하기 전에, 우리는 방문객의 시간대를 고려해서 어떠한 날짜와 시간을 처리해야 한다.따라서 우리는 그것을 플러그인에 분배하는 방법이 필요하다.다행히도 JavaScript 때문에 매우 간단합니다.마스터 app.js 파일을 편집합니다.
// ./assets/js/app.js

// ...

const liveSocket = new LiveSocket('/live', Socket, {
  params: {
    _csrf_token: csrfToken,
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  },
});

// ...
우리는 Intl.DateTimeFormat.prototype.resolvedOptions()timezone값을 사용하여livesocket 연결에 새로운 timeZone 파라미터를 추가합니다. 이 파라미터는 현재 사용자 브라우저의 지역 설정, 날짜, 시간을 반영하는 새로운 대상을 되돌려줍니다.우리가 이전 부분에서 만든 실시간 공공 세션을 기억하십니까?timezone 매개 변수를 고려하여 편집합니다.
# ./lib/calendlex_web/live/init_assigns.ex

defmodule CalendlexWeb.Live.InitAssigns do
  import Phoenix.LiveView

  def on_mount(:default, _params, _session, socket) do
    owner = Application.get_env(:calendlex, :owner)
    time_zone = get_connect_params(socket)["timezone"] || owner.time_zone

    socket =
      socket
      |> assign(:owner, owner)
      |> assign(:time_zone, time_zone)

    {:cont, socket}
  end
end
우리는 get_connect_params/1을 사용하여 플러그인의 연결 매개 변수에서 값을 얻고 플러그인에 분배합니다.timezone이 없으면 소유자의 시간대를 기본값으로 설정합니다.이제 CalendlexWeb.EventTypeLive으로 돌아가서 달력 구축에 필요한 적절한 할당을 추가하겠습니다.
# ./lib/calendlex_web/live/event_type_live.ex

defmodule CalendlexWeb.EventTypeLive do
  alias Calendlex.{EventType, Repo}

  alias Timex.Duration

  def mount(%{"event_type_slug" => slug}, _session, socket) do
    case Calendlex.get_event_type_by_slug(slug) do
      {:ok, event_type} ->
        socket =
          socket
          # ...
          |> assign_dates()

        {:ok, socket}

      # ...
    end
  end

  defp assign_dates(socket) do
    current = Timex.today(socket.assigns.time_zone)
    beginning_of_month = Timex.beginning_of_month(current)
    end_of_month = Timex.end_of_month(current)

    previous_month =
      beginning_of_month
      |> Timex.add(Duration.from_days(-1))
      |> date_to_month()

    next_month =
      end_of_month
      |> Timex.add(Duration.from_days(1))
      |> date_to_month()

    socket
    |> assign(current: current)
    |> assign(beginning_of_month: beginning_of_month)
    |> assign(end_of_month: end_of_month)
    |> assign(previous_month: previous_month)
    |> assign(next_month: next_month)
  end

  defp date_to_month(date_time) do
    Timex.format!(date_time, "{YYYY}-{0M}")
  end
end
mount/3 함수의 즐거움 경로에서 우리는 새로운 assign_dates 함수를 호출했는데 이 함수는 socket을 받아들인다.이 함수는 현재 날짜, 현재 달의 시작과 끝을 계산하여 소켓에 분배합니다."{YYYY}-{0M}" 형식으로 다음 달과 지난달을 할당합니다. 이 형식으로 다른 달을 훑어보겠습니다.보기의 템플릿으로 돌아가서 캘린더를 만듭니다.
# ./lib/calendlex_web/live/event_type_live.html.heex

<div class="w-3/5 mx-auto">
  <div class="flex flex-auto p-6 mb-2 bg-white border border-gray-200 shadow-md rounded-md gap-x-2">
    <div class="flex-1">
        # ...

        <%= @event_type.duration %> min
      </div>
    </div>
    <div class="px-8 border-l border-gray-100">
      <header class="mb-8">
          <h3 class="text-lg font-semibold text-gray-900">Select a date & time</h3>
      </header>
      <EventType.calendar
              id="calendar"
              current_path={Routes.live_path(@socket, CalendlexWeb.EventTypeLive, @event_type.slug)}
              previous_month={@previous_month}
              next_month={@next_month}
              current={@current}
              end_of_month={@end_of_month}
              beginning_of_month={@beginning_of_month}
              time_zone={@time_zone} />
    </div>
  </div>
</div>
우리는 기존의 CalendlexWeb.Components.EventType 모듈에서 새로운 함수 구성 요소를 사용하여 달력을 나타낼 것이다.뷰에서 이 모듈의 별칭을 지정하고 새로운 기능을 구현합니다.
# ./lib/calendlex/event_type/repo.ex

defmodule Calendlex.EventType.Repo do
  # ...

  alias CalendlexWeb.Components.EventType

  #...
end
# ./lib/calendlex_web/live/components/event_type.ex

defmodule CalendlexWeb.Components.EventType do
  use Phoenix.Component

  # ...

  def calendar(
        %{
          current_path: current_path,
          previous_month: previous_month,
          next_month: next_month
        } = assigns
      ) do
    previous_month_path = build_path(current_path, %{month: previous_month})
    next_month_path = build_path(current_path, %{month: next_month})

    assigns =
      assigns
      |> assign(previous_month_path: previous_month_path)
      |> assign(next_month_path: next_month_path)

    ~H"""
    <div>
      <div class="flex items-center mb-8">
        <div class="flex-1">
          <%= Timex.format!(@current, "{Mshort} {YYYY}") %>
        </div>
        <div class="flex justify-end flex-1 text-right">
          <%= live_patch to: @previous_month_path do %>
            <button class="flex items-center justify-center w-10 h-10 text-blue-700 align-middle rounded-full hover:bg-blue-200">
              <i class="fas fa-chevron-left"></i>
            </button>
          <% end %>
          <%= live_patch to: @next_month_path do %>
            <button class="flex items-center justify-center w-10 h-10 text-blue-700 align-middle rounded-full hover:bg-blue-200">
              <i class="fas fa-chevron-right"></i>
            </button>
          <% end %>
        </div>
      </div>
      <div class="mb-6 text-center uppercase calendar grid grid-cols-7 gap-y-2 gap-x-2">
        <div class="text-xs">Mon</div>
        <div class="text-xs">Tue</div>
        <div class="text-xs">Wed</div>
        <div class="text-xs">Thu</div>
        <div class="text-xs">Fri</div>
        <div class="text-xs">Sat</div>
        <div class="text-xs">Sun</div>
      </div>
      <div class="flex items-center gap-x-1">
        <i class="fas fa-globe-americas"></i>
        <%= @time_zone %>
      </div>
    </div>
    """
  end

  defp build_path(current_path, params) do
    current_path
    |> URI.parse()
    |> Map.put(:query, URI.encode_query(params))
    |> URI.to_string()
  end
end
calendar은 분배된 previous_monthnex_month의 값을 이용하여 월간 내비게이션 경로를 생성한다. current_pathmonth이라는 검색 문자열 파라미터와 상응하는 값으로 구성된다.우리 왜 이러는 거야?달력에 서로 다른 달을 나타내려면 current, beginning_of_monthend_of_month의 값을 갱신해야 한다.다음과 같은 두 가지 방법이 있습니다.
  • 은 매달 내비게이션 단추에 클릭 이벤트를 추가하고liveview에 해당하는 handle_event/3 리셋 함수를 추가합니다.
  • 은 같은 URL에 live_patch/2을 사용하고 우리가 필요로 하는 검색 문자열 파라미터를 추가하고liveview 모듈에서 해당하는 handle_params/3 리셋 함수를 실현한다.
  • 이런 상황에서 두 번째 선택은 첫 번째 선택보다 두 가지 장점이 있다.우선 handle_params/3mount/3 이후와 초기 렌더링 전에 호출되기 때문에 초기 마운트할 때 논리를 다시 사용할 수 있습니다.그 다음으로 가장 중요한 것은 브라우저의 URL도 업데이트하기 때문에 사용자가 페이지를 새로 고치면 보기 상태를 구축하는 데 사용하는 모든 파라미터를 잃어버리지 않습니다.브라우저로 돌아가서 다음 항목이 표시되는지 확인합니다.

    지금까지는 괜찮아 보였어요.그러나 < 또는 > 버튼 중 하나를 클릭하여 다른 달을 표시하면 터미널에서 다음과 같은 오류를 볼 수 있습니다.
    [error] GenServer #PID<0.617.0> terminating
    ** (UndefinedFunctionError) function CalendlexWeb.EventTypeLive.handle_params/3 is undefined or private
        (calendlex 0.1.0) CalendlexWeb.EventTypeLive.handle_params(%{"event_type_slug" => "15-minute-meeting", "month" => "2021-12"}, "http://localhost:4000/15-minute-meeting?month=2021-12", #Phoenix.LiveView.Socket<assigns: %{__changed__: %{}, beginning_of_month: ~D[2021-11-01], current: ~D[2021-11-26], end_of_month: ~D[2021-11-30], event_type: %Calendlex.EventType{__meta__: #Ecto.Schema.Metadata<:loaded, "event_types">, color: "blue", description: "Short meeting call.", duration: 15, id: "51bd2b10-783f-42f5-bc89-57e4253d0127", inserted_at: ~N[2021-11-23 07:17:59], name: "15 minute meeting", slug: "15-minute-meeting", updated_at: ~N[2021-11-23 07:17:59]}, flash: %{}, live_action: nil, next_month: "2021-12", owner: %{name: "Bigardone", time_zone: "Europe/Madrid"}, page_title: "15 minute meeting", previous_month: "2021-10", time_slots: [], time_zone: "Europe/Madrid"}, endpoint: CalendlexWeb.Endpoint, id: "phx-FrsEfVWph4A5eQCE", parent_pid: nil, root_pid: #PID<0.617.0>, router: CalendlexWeb.Router, transport_pid: #PID<0.611.0>, view: CalendlexWeb.EventTypeLive, ...>)
        (phoenix_live_view 0.17.5) lib/phoenix_live_view/utils.ex:369: anonymous fn/5 in Phoenix.LiveView.Utils.call_handle_params!/5
        (telemetry 1.0.0) /Users/ricardogarciavega/projects/elixir/calendlex/deps/telemetry/src/telemetry.erl:293: :telemetry.span/3
        (phoenix_live_view 0.17.5) lib/phoenix_live_view/channel.ex:117: Phoenix.LiveView.Channel.handle_info/2
        (stdlib 3.15) gen_server.erl:695: :gen_server.try_dispatch/4
        (stdlib 3.15) gen_server.erl:771: :gen_server.handle_msg/6
        (stdlib 3.15) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
    
    오류를 수정하려면 handle_params/3 모듈에서 CalendlexWeb.EventTypeLive 콜백을 수행해야 합니다.
    # ./lib/calendlex_web/live/event_type_live.ex
    
    defmodule CalendlexWeb.EventTypeLive do
      use CalendlexWeb, :live_view
    
      alias CalendlexWeb.Components.EventType
    
      def mount(%{"event_type_slug" => slug}, _session, socket) do
        case Calendlex.get_event_type_by_slug(slug) do
          {:ok, event_type} ->
            socket =
              socket
              |> assign(event_type: event_type)
              |> assign(page_title: event_type.name)
              # we remove this line
              # |> assign_dates()
    
            {:ok, socket}
    
          {:error, :not_found} ->
            {:ok, socket, layout: {CalendlexWeb.LayoutView, "not_found.html"}}
        end
      end
    
      def handle_params(params, _uri, socket) do
        # we call `assign_dates` passing `params` as well
        socket = assign_dates(socket, params)
    
        {:noreply, socket}
      end
    
      # this function now accepts an additional parameter `params`
      defp assign_dates(socket, params) do
        current = current_from_params(socket, params)
    
        # ...
      end
    
      defp current_from_params(socket, %{"month" => month}) do
        case Timex.parse("#{month}-01", "{YYYY}-{0M}-{D}") do
          {:ok, current} ->
            NaiveDateTime.to_date(current)
    
          _ ->
            Timex.today(socket.assigns.time_zone)
        end
      end
    
      defp current_from_params(socket, _) do
        Timex.today(socket.assigns.time_zone)
      end
    
      # ...
    end
    
    현재 모듈의 논리는 다음 네 가지로 변경되었습니다.
  • 우선, handle_params/3mount/3 이후에 즉시 호출되기 때문에 우리는 assign_dates/2에서 mount을 호출할 필요가 없기 때문에 이 호출을 삭제할 수 있습니다.
  • 우리는 handle_params/3 리셋 함수를 실현했고 플러그인과 요청에서 받은 매개 변수를 통해 assign_dates/2을 호출했다.
  • 우리는 params 함수에 새로운 매개 변수 assign_dates을 추가하여 current의 값을 계산하는 데 사용한다.
  • 마지막이지만 가장 중요하지 않은 것은 current_from_params/2 함수를 추가했습니다. 이 함수는 플러그인과 파라미터를 받아들여 current을 구축했습니다.
  • 만약 우리가 브라우저로 돌아가 지난달과 다음 달 단추를 다시 눌렀다면, 우리는 브라우저의 URL이 어떻게 업데이트되어 해당하는 달을 보여 주는지 보아야 한다.또한 브라우저를 새로 고치면 표시된 달을 잊지 않습니다.예!

    우리의 달력 차이는 많지 않아 준비가 다 되었다.유일하게 남은 것은 이번 달의 일수를 과장하는 것이다.CalendlexWeb.Components.EventType.calendar/1 함수 구성 요소로 돌아가서 적절한 논리를 실현해 보겠습니다.
    # ./lib/calendlex_web/live/components/event_type.ex
    
    defmodule CalendlexWeb.Components.EventType do
      use Phoenix.Component
    
      # We will implement this module in a minute...
      import CalendlexWeb.LiveViewHelpers
    
      alias __MODULE__
    
      # ...
    
      def calendar(
            %{
              current_path: current_path,
              previous_month: previous_month,
              next_month: next_month
            } = assigns
          ) do
        # ...
    
        ~H"""
        <div>
          # ...
    
          <div class="mb-6 text-center uppercase calendar grid grid-cols-7 gap-y-2 gap-x-2">
            <div class="text-xs">Mon</div>
            <div class="text-xs">Tue</div>
            <div class="text-xs">Wed</div>
            <div class="text-xs">Thu</div>
            <div class="text-xs">Fri</div>
            <div class="text-xs">Sat</div>
            <div class="text-xs">Sun</div>
            <%= for i <- 0..@end_of_month.day - 1 do %>
              <EventType.day
                index={i}
                current_path={@current_path}
                date={Timex.shift(@beginning_of_month, days: i)}
                time_zone={@time_zone} />
            <% end %>
          </div>
          # ...
        </div>
        """
      end
    
      # ...
    
      def day(%{index: index, current_path: current_path, date: date, time_zone time_zone} = assigns) do
        date_path = build_path(current_path, %{date: date})
        disabled = Timex.compare(date, Timex.today(time_zone)) == -1
        weekday = Timex.weekday(date, :monday)
    
        class =
          class_list([
            {"grid-column-#{weekday}", index == 0},
            {"content-center w-10 h-10 rounded-full justify-center items-center flex", true},
            {"bg-blue-50 text-blue-600 font-bold hover:bg-blue-200", not disabled},
            {"text-gray-200 cursor-default pointer-events-none", disabled}
          ])
    
        assigns =
          assigns
          |> assign(disabled: disabled)
          |> assign(:text, Timex.format!(date, "{D}"))
          |> assign(:date_path, date_path)
          |> assign(:class, class)
    
        ~H"""
        <%= live_patch to: @date_path, class: @class, disabled: @disabled do %>
          <%= @text %>
        <% end %>
        """
      end
    end
    
    일수를 표시하기 위해 현재 달의 일수를 순환하고 day/1이라는 새 함수 구성 요소를 호출하여 다음 값을 할당합니다.
  • index: 순환 중인 현재 인덱스.
  • current_path: 현재 LiveView의 경로입니다.
  • date: 순환 중인 현재 날짜입니다.
  • time_zone: 방문객의 시간대.
  • 이 구성 요소는 현재 경로를 가리키는 링크로 구성되어 있으며, date이라는 새로운 검색 문자열 인자가 추가되었습니다.만약 날짜가 오늘보다 이르면, 우리는 과거의 사건을 방지하기 위해 링크를 비활성화할 것입니다.서로 다른 요소에 따라 링크의 양식을 설정하고 싶기 때문에, 우리는 새로운 helper 모듈을 사용하여 class 속성의 값을 생성할 것입니다.계속해서 도움말 모듈을 만들겠습니다.
    # ./lib/calendlex_web/live/live_view_helpers.ex
    
    defmodule CalendlexWeb.LiveViewHelpers do
      def class_list(items) do
        items
        |> Enum.reject(&(elem(&1, 1) == false))
        |> Enum.map(&elem(&1, 0))
        |> Enum.join(" ")
      end
    end
    
    class_list/1은 두 원소 모듈의 목록을 가져왔는데 그 중에서 첫 번째 원소는 클래스 이름을 포함하는 문자열이고 두 번째 원소는 이런 클래스를 적용해야 하는지의 브리 값을 나타낸다.목록의 모든 항목을 옮겨다니며 잘못된 항목을 거부하고 나머지 항목을 연결합니다.우리의 day 구성 요소에 대해, 우리는 단지 한 달 첫날에 어떤 스타일을 추가하고, 사용하지 않거나 사용하지 않을 때 다른 스타일을 추가하고 싶을 뿐입니다. 우리는 흔히 볼 수 있는 스타일도 있습니다."grid-column-#{weekday}"은 사용자 정의 클래스로, CSS Grid Layout을 사용하여 한 달 첫날을 지정하므로 기본 CSS 파일에 추가합니다.
    /* ./assets/css/app.css */
    
    /* ... */
    
    .grid-column-1 {
      grid-column: 1;
    }
    
    .grid-column-2 {
      grid-column: 2;
    }
    
    .grid-column-3 {
      grid-column: 3;
    }
    
    .grid-column-4 {
      grid-column: 4;
    }
    
    .grid-column-5 {
      grid-column: 5;
    }
    
    .grid-column-6 {
      grid-column: 6;
    }
    
    .grid-column-7 {
      grid-column: 7;
    }
    
    브라우저로 돌아가면 달력의 휘황찬란함을 볼 수 있습니다.

    달력이 어떻게 업데이트되는지 살펴봐야 한다. 만약 우리가 달에서 내비게이션을 한다면 새로운 달이 나타날 것이다.하나만 남았습니다: 우리가 날짜를 눌렀을 때 호출된 실시간 패치에서 새로운 date 파라미터를 처리합니다:
    # ./lib/calendlex_web/live/event_type_live.ex
    
    defmodule CalendlexWeb.EventTypeLive do
      use CalendlexWeb, :live_view
    
      # ...
    
      defp current_from_params(socket, %{"date" => date}) do
        case Timex.parse(date, "{YYYY}-{0M}-{D}") do
          {:ok, current} ->
            NaiveDateTime.to_date(current)
    
          _ ->
            Timex.today(socket.assigns.time_zone)
        end
      end
    
      # ...
    end
    
    우리는 이전에 month 매개 변수를 실현할 때 이미 모든 것을 준비했기 때문에 current_from_params 매개 변수에 새로운 버전의 date 함수를 추가하고 이를 현재 날짜로 설정하기만 하면 된다.만약에 우리가 지금 날짜를 클릭하면 브라우저의 URL이 어떻게 업데이트되는지 볼 수 있고 date 파라미터가 추가되어 있습니다. 만약에 우리가 브라우저의 페이지를 새로 고치면 달력은 우리가 선택한 날짜에 나타날 것입니다.

    이 부분은 여기까지입니다.다음 섹션에서는 사용자가 선택한 이벤트 유형과 날짜를 사용하여 하루에 사용할 수 있는 모든 기간을 보여 줍니다.방문객이 폼을 제출한 후에 새로운 이벤트를 만들 수 있도록 schedule 이벤트 라이브 뷰를 구현합니다.또한 live demo의 최종 결과를 보거나 source code을 볼 수 있습니다.
    즐거운 코딩!

    비카덴 / calendlex


    Phoenix LiveView를 통한 간편한 클론 복제

    좋은 웹페이지 즐겨찾기