Home

Awesome

form-validator

ClojureScript library to validate forms.

Rationale

Why? I need it myself. But I didn't find any library which satisfy me, so I wrote my own.

Read my article form validation to learn more rationales.

Tutorial and Demo

Discover it naturally by real code: https://kwladyka.github.io/form-validator-cljs/

<a href="https://kwladyka.github.io/form-validator-cljs/"><img src="https://storage.googleapis.com/kwladyka/form-validator-cljs/demo.gif"></a>

Please keep in mind it is an example. It could easy take actions on different events on-change / on-blur / button click. All is your choice.

Add dependency

Clojars Project

Require in ns

(:require [form-validator.core :as form-validator])

Only if you use reagent

To be compatible with reagent library, needs to use reagent.core/atom instead clojure.core/atom.

(ns app.core
  (:require [reagent.core :as r]
            [form-validator.core :as form-validator]))

;; First line in core ns or dedicated init fn is a right place
(swap! form-validator/conf #(merge % {:atom r/atom}))

TL;DR

Init form

(-> {:names->value {:email ""
                    :password ""}
     :form-spec ::spec/form
    (form-validator/init-form))

return atom contained map:

{:form-spec :app.spec/form
 :names->value {:email "" :password ""}
 :names->invalid {:email [:app.spec/form :app.spec/email] :password [:app.spec/form :app.spec/password :app.spec/password-not-empty]}
 :names->show #{}
 :names->validators {}}

Then you can use functions from ns form-validator.core:

Specification

Init form


;; clojure.spec.alpha

(s/def ::email (s/and string? (partial re-matches #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$")))

(s/def ::password-not-empty not-empty)
(s/def ::password-length #(<= 6 (count %)))
(s/def ::password (s/and string? ::password-not-empty ::password-length))

(s/def ::form (s/keys :req-un [::email ::password]
                      :opt-un [::password-repeat]))

;; form-valiadtor

(-> {:names->value {:email ""
                    :password ""}
     :form-spec ::form
     :names->validators {:email [email-exist?]
                         :password-repeat [password-repeat? ::spec-key]}}
    (form-validator/init-form))

You can use :form-spec and :names->validators together. :form-spec is checked first.

Interact with form

(init-form ...) return atom:

{:form-spec :app.spec/form
 :names->value {:email "", :password ""}
 :names->invalid {:email [::form ::form-map ::email]
                  :password [::form ::form-map ::password ::password-not-empty]}
 :names->show #{}
 :names->validators {:email #object[cljs$core$sp1], :password-repeat #object[cljs$core$sp1]}}

Messages

;; Check error for input name "password"
(->> {::email "Typo? It doesn't look valid."
      ::password "Minimum 6 characters and one special character !@#$%^&*."
      :password-not-equal "Repeat password has to be the same."}
     (form-validator/?show-message form :password))

Based on [::form ::form-map ::password ::password-not-empty] it is trying to find ::password-not-empty message. Map not contain message for this spec. Then try to find ::password and return message. If not find, going deeper. If not find any, return true.

If reason of fail is not a vector, then it is returning as it is. For example "cutom message" or {:level :warn :msg "This is only warning."}. This is dedicated for fn validators.

Tips & Tricks & FAQ


Everything below this line is mainly for myself as a maintainer of this library.

Developing

Library has to be always check with web browsers manually! Not only automated tests. The reasons are differences between web browsers and practical aspects of usability vs imagination :)

To do it use doc branch from this repository.

After all make a commit to readme with new sha hash for deps.edn.

Tests

clj -A:test:test-once

clj -A:test:test-watch