How have you done Clojurescript form validation?

For those implementing standard web apps in Clojurescript, do you have favorite libraries (probably Javascript?) for form validation? In particular I could use a library that could support three timing options: as-you-type validation (e.g. phone numbers or ID not allowing letters to be input), on-blur (e.g. “that isn’t a valid email address”), and on-submit (preferably with scrolling up to the erroneous fields). What have you found that blends nicely with Clojurescript? Or is there a good hidden solution out of the Closure library?

4 Likes

Right now looking over these might be promising (haven’t looked into clean-ness of CLJS interop yet, though): https://www.cssscript.com/best-javascript-form-validator/ . I’m surprised not to see much form-related stuff in Closure; the closest I could find is this: https://github.com/google/closure-library/blob/3d08bd72451ab11676cc68d6bae34fcb8d78adb8/closure/goog/events/inputhandler_test.js

This is a very good question. Hoping to see some answers, tips and best practices coming!

For selfish reasons I’d especially like to see some libraries for using with citrus, since I prefer to have my rum that way. :smile:

1 Like

Honestly, every library I’ve ever tried for that has been buggy, error prone, and at the end of the day more time consuming than writing your own specific code. There are just far too many options a library would have to handle. Rolling your own isn’t that hard, so I’ve found taking a day to do that is better than the random surprises a library will drop on you.

2 Likes

In the link you post, I think that is kind of an UI library that hook on the input tag.

First, the UI. I rarely use pre-built input component. It’s easy to build my own. Just a div with some styles, and locate it at the correct position.

Second, how component work. With re-frame, you can have reg-sub for an error, which take the input from the subscribe of a form value. And the component receive these two subscribes.

I have a reagent/reframe library I built that we use in many of our in-house apps for forms; I’m looking for a good way to plug validation in, and don’t want to reinvent the wheel if I can avoid it

We’ve tried different ways. It’s been quite a challenge.

One of our larger re-frame code bases borrowed from a proven approach. The django form validation code isn’t written in a functional style but this gave us concepts to build on.

At a high level it boils down to:

  • Form state lives in app-db.
  • Subscriptions applies logic to form-state to do validation. From this we get cleaned-data and errors. We also have a subscription for inputs to get values.
  • Views for inputs
  • Inputs dispatch when the value changes (often on-blur [1]).
  • Event handler updates “form-state” in the app-db.
  • (rinse lather repeat).

For more complex requirements we go further. The logic actually modifies the form field metadata so that we can hide fields, change whether fields are required, modify the value of fields. In those cases the data flow is painfully iterative, we mark which fields depend on other fields then iterate through them in order modifying both the form metadata and form state. It works but I would love a better approach.

Now I try to write this down I suspect it is a bit confusing.

I guess my main take away is that having someone catalog all possible approaches would be a fantastic resource.

[1] We need to adapt our approach based on this react blog post

1 Like

I appreciate the respect you give this topic. In many places (e.g. reddit) I see “just roll your own. It’s easy.” In fact it’s a complex task.

The bit I was unclear on in your message is when you mentioned subscrpitions applying logic to do validation. What did you mean by this? Admittedly I’m not a master of re-frame subscriptions yet…

We have a form-clean function which takes form state and returns data and errors.

When the UI wants to display errors it uses a sub which does form-clean against the form state kept in the app-db.

Oh, I see – so some form of :errors is a first-class path in the app-db, perhaps even with :form-errors some some-path, and then your view with the form will parse those meaningfully. Have you implemented scroll-to-error and changing the view for a form element/input with an error? I’m curious how you’ve approached that common case.

So far I’ve just relied on the default validation functions provided by html5, but they don’t seem to allow all bells and whistles that make some validation nice.

This just out: https://clojure.wladyka.eu/posts/form-validation/

That is an interesting approach. Thanks for sharing the link! I will have to look at his github repo as well: https://github.com/kwladyka/form-validator-cljs

1 Like

I’ve done something very similar on some apps, using cljc specs to check both front and back. But that doesn’t really address my original concerns: reacting to errors and deciding reaction-time

Not ClojureScript, but still a good read on Form Validation with React/Js: https://blog.logrocket.com/react-hook-form-vs-formik-a-technical-and-performance-comparison/

Enjoyed also Krzysztof’s blog about spec+validation. Will definetely toy with form & validation with malli schemas. Schema-based form validation is universally useful, schema-derived forms are valuable in many cases, like in prototyping and technical/admin uis.

1 Like