cl-forms icon indicating copy to clipboard operation
cl-forms copied to clipboard

Validation between fields

Open spapas opened this issue 1 year ago • 5 comments

I want to implement a form similar to this:

(cl-forms:defform register-form (:action "/register/" :method :post)
                  ((username :string :value "" :constraints (list (clavier:is-a-string)
                                                                  (clavier:not-blank)))
                   (password :password :value "")
                   (password-verify :password :value "")
                   (submit :submit :label "Register")))

The fields password and password-verify must match. Is there a way to validate these (forms::validate-form form) ? If not how can I add the extra validation messages for these?

TIA

spapas avatar Oct 14 '24 07:10 spapas

Hi. I have only implemented validation per field, although I think I should also have implemented per whole form, so that validation between fields can be achieved. I think in this case you will have to provide validation for the form yourself. Like a function validate-my-form that calls forms:validate-form, but then also checks the password field values. Let me know if you need help with this, I can try an implementation. Or if you have ideas on how to extend form validation to the whole form. I will think about it.

mmontone avatar Oct 14 '24 10:10 mmontone

If not how can I add the extra validation messages for these?

To add your own validation message follow forms:validate-form implementation in your custom validation function: "Validates a form. Usually called after HANDLE-REQUEST. Returns multiple values; first value is true if the form is valid; second value a list of errors. The list of errors is an association list with elements (<field> . field errors strings list>)."

mmontone avatar Oct 14 '24 10:10 mmontone

Ah ok I thought that maybe there was a way to actually include validation among multiple fields.

For now I have implemented it using a function that verifies the whole form and either returns nil if everything's cool or the form with the errors if there are problems:

(defun register-form-errors (form)
  (if (forms::validate-form form)
      (forms::with-form-field-values (username password password-verify) form
        (cond ((not (equal password password-verify))
                (forms:add-form-error 'password-verify "Passwords do not match" form))
              ((equal username "root")
                (forms:add-form-error 'username "Wrong username" form))
              (t nil)))
      form))

To implement the validation among fields you could add an optional parameter with that function in the form definition, for example:

(cl-forms:defform register-form (:action "/register/" :method :post :validation #'register-validate) where the register-validate would receive the form instance and modify the form if there are errors (using forms:add-form-error f.e).

spapas avatar Oct 14 '24 10:10 spapas

Also we could add a generic form-validation function that a form that wants such validation could override.

spapas avatar Oct 14 '24 11:10 spapas

Ah. I forgot about add-form-error. That's good use. I will think about an implementation for custom form validations.

mmontone avatar Oct 14 '24 11:10 mmontone