ClojureScript library to validate forms.
spec and fn."foo", {:level :warn :msg "foo"} or whatever.on-blur / on-change / immediately after load page / ...re-frame, fulcro or whatever.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.
Discover it naturally by real code: https://kwladyka.github.io/form-validator-cljs/
The best to do after this readme. But if you are inpatient take a look and back here.
{:deps {github-kwladyka/form-validator {:git/url "https://github.com/kwladyka/form-validator-cljs" :sha "0fec75c9046bff3b5c5f37a0bd7f821c1e8edbe0"}}}
The recommended way to do it is to use lein-tool-deps.
Basicly add this plugin and make deps.edn file like above.
(:require [form-validator.core :as form-validator])
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}))
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:
event->names->value! - With on-change / on-blur input event to update values.event->show-message - With on-blur / on-change input event to trigger when show messages in UI.?show-message - Get message to show in UI for input. Also to know if mark input as not valid in UI.form-valid? - true / falsevalidate-form-and-show? - Call validate-form and show all messages. Use with submit button.
;; 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))
:names->value - Form inputs with values to initialize.:opt-un it can be ommited.:form-spec - Spec to validate whole form.:names->validators - Vector of spec keywords and fn. Order matter.spec for form / if checkbox "accept terms" is checked / fn to compare password-repeat / check if user already exist by API during registration.:names->show - #{} with names of inputs to show error messages on start.
Use cases: Form with already filled values.You can use :form-spec and :names->validators together. :form-spec is checked first.
(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]}}
:form-spec - Init form value without any change.:names->value - Values of the form.:names->invalid - Invalid inputs with reasons of validation fail.:names->show - Add name of the input here, when you want to show message in UI.:names->validators - All validators converted to one fn which works similar to some. Check all validators for specific input one by one, unless fail or return nil.:names->validators can contain ::spec-key and fn.:cljs.spec.alpha/problems :via. For example [::form ::form-map ::password ::password-not-empty]. It means spec ::form refer to spec ::form-map, which refer to spec ::password, which refer to spec ::password-not-empty, which failed.fn can return vectors like spec, but also strings, map or any value.;; 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.
atom returned by form-init, add-watch on atom, add functions on top of core functions, use your own functions instead of core ones. It is designed to let you make custom things. In most of cases you really don't need to do it. It could be useful if you want to make your module based on this one.form-valid? function or make two form-init (first for errors and second for warnings). I decided to not make it as part of this library, because it is individual thing for project.Everything below this line is mainly for myself as a maintainer of this library.
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.
clj -A:test:test-once
clj -A:test:test-watch
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |