Skip to content

Instantly share code, notes, and snippets.

@mcrumm
Last active July 22, 2024 18:33
Show Gist options
  • Save mcrumm/88313d9f210ea17a640e673ff0d0232b to your computer and use it in GitHub Desktop.
Save mcrumm/88313d9f210ea17a640e673ff0d0232b to your computer and use it in GitHub Desktop.
flatpickr + LiveView example
// assets/js/app.js
// ...
import Pickr from "./pickr"
const hooks = {
Pickr
}
// ...
let liveSocket = new LiveSocket("/live", Socket, { hooks, params: { _csrf_token: csrfToken } })
// assets/js/pickr/index.js
import flatpickr from "flatpickr";
const Pickr = {
mounted() {
this.pickr = flatpickr(this.el, {
wrap: true,
altInput: this.el.dataset.pickrAltFormat ? true : false,
altFormat: this.el.dataset.pickrAltFormat || "d M Y",
dateFormat: this.el.dataset.pickrDateFormat || "Y-m-d"
})
},
updated() {
const altFormat = this.el.dataset.pickrAltFormat
const wasFormat = this.pickr.config.altFormat
if (altFormat !== wasFormat) {
this.pickr.destroy()
this.pickr = flatpickr(this.el, {
wrap: true,
altInput: this.el.dataset.pickrAltFormat ? true : false,
altFormat: this.el.dataset.pickrAltFormat || "d M Y",
dateFormat: this.el.dataset.pickrDateFormat || "Y-m-d"
})
}
},
destroyed() {
this.pickr.destroy()
}
}
export default Pickr
# lib/my_app_web/live/pickr_live.ex
defmodule MyAppWeb.PickrLive do
use MyAppWeb, :live_view
@impl Phoenix.LiveView
def render(assigns) do
~L"""
<h2>flatpickr example</h2>
<form id="pickr-form" action="#" phx-change="validate">
<div id="starts-at-pickr" class="flatpickr" phx-update="ignore" phx-hook="Pickr" data-pickr-alt-format="<%= @format %>">
<label for="starts-at">Starts at</label>
<input type="text" id="starts-at" name="pickr[starts_at]" placeholder="Select Start Date.." data-input />
</div>
<div id="ends-at-pickr" class="flatpickr" phx-update="ignore" phx-hook="Pickr" data-pickr-alt-format="<%= @format %>">
<label for="ends-at">Ends at</label>
<input type="text" id="ends-at" name="pickr[ends_at]" placeholder="Select End Date.." data-input />
</div>
</form>
<%= if @values do %>
<p>Values: <code><%= @values %></code></p>
<% end %>
<hr />
<form id="format" action="#" phx-change="format">
<label>Alt Format</label>
<input type="text" name="format" value="<%= @format %>"/>
</form>
"""
end
@impl Phoenix.LiveView
def handle_event("validate", %{"pickr" => _} = values, socket) do
{:noreply, assign(socket, :values, inspect(values, pretty: true))}
end
def handle_event("format", %{"format" => format}, socket) do
{:noreply, assign(socket, :format, format)}
end
@impl Phoenix.LiveView
def mount(_, _, socket) do
{:ok, socket |> assign(:values, nil) |> assign(:format, "")}
end
end
@micahsoftdotexe
Copy link

Greetings, I am new to Phoenix and LiveView. I am trying to implement this but the issues I am having pertain to the css. It appears as though the css renders the datepicker internals at the bottom of the page constantly and does not wait to be clicked on the datepicker input. Am I doing something wrong or do I need to do some more work for modern versions of liveview?

@absowoot
Copy link

@micahsoftdotexe I had a similar issue and the updates below resolved it for me:

<div id="date-pickr" phx-update="ignore">
    <div id="starts-at-pickr" class="flatpickr" phx-hook="Pickr" data-pickr-alt-format="<%= @format %>">
      <label for="starts-at">Starts at</label>
      <input type="text" id="starts-at" name="pickr[starts_at]" placeholder="Select Start Date.." data-input />
    </div>
</div>
const Pickr = {
    mounted() {
        this.pickr = flatpickr(this.el, {
            wrap: true,
            appendTo: this.el.querySelector("input"),
            static: true,
            altInput: this.el.dataset.pickrAltFormat ? true : false,
            altFormat: this.el.dataset.pickrAltFormat || "d M Y",
            dateFormat: this.el.dataset.pickrDateFormat || "Y-m-d",
        });
    },
    updated() {
        const altFormat = this.el.dataset.pickrAltFormat;
        const wasFormat = this.pickr.config.altFormat;
        if (altFormat !== wasFormat) {
            this.pickr.destroy();
            this.pickr = flatpickr(this.el, {
                wrap: true,
                appendTo: this.el.querySelector("input"),
                static: true,
                altInput: this.el.dataset.pickrAltFormat ? true : false,
                altFormat: this.el.dataset.pickrAltFormat || "d M Y",
                dateFormat: this.el.dataset.pickrDateFormat || "Y-m-d",
            });
        }
    },
    destroyed() {
        this.pickr.destroy();
    },
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment