Password Box
Subscribe to a paid plan to get instant access to this lesson.
Download  Video time: 26m08s

Password Box

Don't you hate password boxes that have all sorts of crazy password requirements but don't tell you what they are? Or they do tell you but they don't give you any feedback about which ones you've passed?

Imagine writing one of these in just 62 lines of ClojureScript. We write two custom validations: minimum length and a minimum entropy.

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.password
  (:require [reagent.core :as reagent]
            [re-frame.core :as rf]))

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

(defn ui []
  [:div
   [:input {:type :password :value "my-password"}]])

(defonce _init (rf/dispatch-sync [:initialize]))
(reagent/render [ui] (js/document.getElementById "student-container"))            
          
Loading compiler
              
                (ns teacher.password
  (:require [reagent.core :as reagent]
            [re-frame.core :as rf]))

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

(def password-validations
  [["At least 12 characters."
    (fn [s]
      (>= (count s) 12))]
   ["At least 50% unique characters."
     (fn [s]
       (-> s
           set
           count
           (/ (count s))
           (>= 0.5)))
     ]])

(defn password-box [pw]
  (let [s (reagent/atom {:value pw})]
    (fn []
      (let [validations (for [[desc f] password-validations]
                          [desc (f (:value @s))])
            valid? (every? identity (map second validations))
            color (when (:dirty? @s) (if valid? "green" "red"))]
      [:form 
       [:label {:style {:color color}} "Password"]
      [:input {:type (if (:show? @s) :text :password)
               :style {:width "100%"
                       :border (str "1px solid " color)}
               :value (:value @s)
               :on-focus #(swap! s assoc :focus? true)
               :on-blur #(swap! s assoc :dirty? true)
               :on-change #(swap! s assoc
                                  :dirty?
                                  true
                                  :value
                                  (-> % .-target .-value))}]
       [:label [:input {:type :checkbox
                        :checked (:show? @s)
                        :on-change #(swap! s assoc
                                           :show?
                                           (-> % .-target .-checked))}]
        " Show password?"]
       (for [[desc valid?] validations]
         (when (:focus? @s)
           [:div
          {:style {:color (when (:dirty? @s) (if valid? "green" "red"))}}
          (when (:dirty? @s) (if valid? "✔ " "✘ ")) desc]))
       ] 
      ))))

(defn ui []
  [:div
   [password-box ""]])

(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