Download  Video time: 25m14s

Collapsible Panel

We create a collapsible panel component. You give it a title and a child and it will hide the child inside until you click the panel.

We use a number of techniques in this component, including component-local state, React refs, CSS animation, and Re-frame events and subscriptions.

Code is available: lispcast/building-re-frame-components

You can checkout the code in your local repo with this command:

$CMD git clone git@github.com:lispcast/building-re-frame-components.git
$CMD cd building-re-frame-components          

Loading compiler
            
              (ns student.collapsible-panel
  (:require [reagent.core :as reagent]
            [re-frame.core :as rf]))

(rf/reg-event-db
  :initialize
  (fn [_ _]
    {}))

(defn ui []
  [:div
   [:h1 "Edit this string in the code"]])

(defonce _init (rf/dispatch-sync [:initialize]))
(reagent/render [ui] (js/document.getElementById "student-container"))            
          
Loading compiler
              
                (ns teacher.collapsible-panel
  (:require [reagent.core :as reagent]
            [re-frame.core :as rf]))
 
(rf/reg-event-db
  :teacher/initialize
  (fn [_ _]
    {}))

(rf/reg-event-db
  :teacher/toggle-panel
  (fn [db [_ id]]
    (update-in db [:panels id] not)))

(rf/reg-sub
  :teacher/panel-state
  (fn [db [_ id]]
    (get-in db [:panels id])))

(defn example-component []
  (let [s (reagent/atom 0)]
    (js/setInterval #(swap! s inc) 1000)
    (fn []
      [:div @s])))

(defn panel [id title & children]
  (let [s (reagent/atom {:open false})]
    (fn [id title & children]
      (let [open? @(rf/subscribe [:teacher/panel-state id])
            child-height (:child-height @s)]
        [:div
         [:div {:on-click #(rf/dispatch [:teacher/toggle-panel id])
                :style {:background-color "#ddd"
                        :padding "0 1em"}}
          [:div {:style {:float "right"}}
           (if open? "-" "+")]
          title]
         [:div {:style  {:overflow "hidden"
                         :transition "max-height 0.8s"
                         :max-height (if open? child-height 0)}}
          [:div {:ref #(when %
                         (swap! s assoc :child-height (.-clientHeight %)))
                 :style {:background-color "#eee"
                         :padding "0 1em"}
                 }
           children]]]))))

(defn ui []
  [:div
   [panel :ex-1 "Example component" [example-component]]])

(defonce _init (rf/dispatch-sync [:teacher/initialize]))
(reagent/render [ui] (js/document.getElementById "teacher-container"))              
            

Building Re-frame Components

Collapsible Panel free 25 min
Sortable Table 34 min
Inline Editable Field 29 min
Progress Bar 30 min
Password Box 26 min
Sortable Table in the Database 25 min
Tag Editor 26 min
Markdown Editor with Live Preview 9 min
Externally Managed Components 12 min
Accordion Component 27 min
Draggable List 36 min
Expanding Table 13 min
Filterable List 22 min
Username Box 1 hr
Username and Password Refactoring 22 min
User-Password Further Refactoring 17 min
User Registration 1 16 min
User Registration 2 28 min
User Registration 3 25 min
Next lesson:

Sortable Table

We build a reusable sortable table component using Re-frame and ClojureScript.