React Interop
Fork doesn't render anything, which means it works with any component
that accepts value and change handler props. This includes JavaScript
React components accessed via ClojureScript interop. The pattern is
always the same: read the current value from
values, write updates via
set-values.
This example integrates react-dates (both single date and date range pickers) into a Fork form alongside a standard text input. The datepicker components are plain Reagent wrappers around the JavaScript library.
Single Date Picker
The single date picker stores a Moment.js object as the field value.
Focus state is managed through Fork's
state ratom directly, keeping the datepicker's
open/closed state alongside the form data:
(defn react-dates-single-date-picker
[k {:keys [values state set-values]}]
[:> js/ReactDates.SingleDatePicker
{:date (get values k)
:display-format "DD MMM YYYY"
:on-focus-change
(fn [e]
(swap! state #(assoc-in % [:focus k] (.-focused e))))
:focused (get-in @state [:focus k])
:on-date-change #(set-values {k %})}])
The key insight: set-values accepts any value
type, not just strings. The Moment.js date object goes straight into
Fork's state and comes back out via values.
Date Range Picker
The range picker works the same way, except the value is a map with
:startDate and
:endDate keys:
(defn react-dates-date-range-picker
[k {:keys [values state set-values]}]
[:> js/ReactDates.DateRangePicker
{:start-date (get-in values [k :startDate])
:end-date (get-in values [k :endDate])
:display-format "DD MMM YYYY"
:on-focus-change
(fn [e]
(swap! state #(assoc-in % [:focus k] e)))
:focused-input (get-in @state [:focus k])
:on-dates-change
#(set-values {k (js->clj % :keywordize-keys true)})}])Full Form
Both datepickers alongside a standard text input in one form.
:keywordize-keys true is enabled so all
field names are keywords, and
normalize-name converts them for DOM
attributes:
(ns examples.datepicker
(:require
;; for CSS use:
;; https://unpkg.com/react-dates@16.3.2/lib/css/_datepicker.css
[cljsjs.react-dates]
[cljs.pprint :as pprint]
[fork.reagent :as fork]))
(defn view []
[fork/form
{:keywordize-keys true
:prevent-default? true
:on-submit #(js/alert (:values %))
:initial-values
{:dummy/input "Just an input"
:single-date-picker (js/moment)
:date-range-picker {:startDate (js/moment)}}}
(fn [{:keys [state form-id values normalize-name
handle-change handle-blur handle-submit]
:as props}]
[:div
[:pre (with-out-str (pprint/pprint @state))]
[:form
{:id form-id
:on-submit handle-submit}
[:div
[:label "Dummy input"]
[:input
{:type "text"
:name (normalize-name :dummy/input)
:value (:dummy/input values)
:on-change handle-change
:on-blur handle-blur}]]
[:br]
[react-dates-single-date-picker
:single-date-picker props]
[:br]
[react-dates-date-range-picker
:date-range-picker props]
[:br]
[:button {:type "submit"} "Submit!"]]])])