(ns myapp.typeahead (:require [reagent.core :as r] [goog.functions :as gf] [myapp.api :as api])) (defn input-control [props] (let [value (r/atom (:default-value props "")) local-change #(reset! value (.. % -target -value))] (fn [{:keys [on-change] :as props}] [:input (assoc props :value @value :on-change (comp #(when (fn? on-change) (on-change %)) local-change))]))) (defn create-typeahead-fetch [opts state] ;; or however you want to build your fetch handler (gf/debounce (partial api/fetch (:remote opts)) (:debounce-ms opts 150))) (defn typeahead [opts] (let [state (r/atom {:open? false :loading? false :results nil :error nil}) fetch (create-typeahead-fetch state opts) toggle #(swap! state update :open? not)] (fn [opts] [:div (if (:open? @state) [input-control {:default-value (:default-value opts "") :on-change fetch}] [button {:on-click toggle} "Show search"]) (if (:loading? @state) [:div "Loading"] [:div (str (count (:results @state)) " results")])])))