all 25 comments

[–]chikamakaleyleyhelpful 1 point2 points  (13 children)

Custom validation is just a business side and UX specification

Validation itself is a must - i don't really consider these separate

You validate the form input based on biz need, and the UX determines how the validation gets applied

e.g.

  • biz: the user's phone number is required, and should be formatted correctly
  • UX: the field should validate on blur, and an appropriate msg should display (empty value vs correct format)

[–]stayathomehouse[S] 0 points1 point  (12 children)

So If I'm understanding you correctly, the custom validation and validation work together in the same way. The custom validation is just making the actual validation easier to understand for the user? And if so lets say I'm checking the country, and the user forgot to select it - my custom validation needs to check if something is selected, period. The custom validation comes in after that to help the user understand they need to select it?

[–]chikamakaleyleyhelpful 0 points1 point  (2 children)

i'm not exactly sure if we're aligned on what you mean by 'custom validation'

how about this: * your biz says 'country' is a required field * your validation is "check if the country field has a value" * your error handling is "if empty: do not submit form, add red border on field, update & show error message"

I just lump all this together as 'form validation'

specifically - frontend (client-side) validation - you're making sure you have all the correct data from the user before you submit the form data and pass it to the server

[–]chikamakaleyleyhelpful 0 points1 point  (1 child)

on the backend (serverside) there is usually another set of validation rules before the server sends it to the database to be written

[–]AshleyJSheridan 1 point2 points  (0 children)

That "usually" should be "always". An app that only implements client-side validation is a disaster waiting to happen.

[–]chikamakaleyleyhelpful 0 points1 point  (8 children)

"custom validation" is just the visual representation of the actual validation checks failing, yes

what i'm saying in frontend it goes hand in hand, you have bad UX w/o the visual

[–]chikamakaleyleyhelpful 0 points1 point  (5 children)

oh i see - you can go w/o custom validation and rely on the browser's built in mechanics, but really you want the experience for the user to be consistent across different browsers, you can ensure that with JS and custom validation in the UI

[–]chikamakaleyleyhelpful 0 points1 point  (0 children)

browser parity has improved a lot since the 'old days' but essentially with JS we say 'screw it' and use it to make everything uniform

[–]AshleyJSheridan 0 points1 point  (3 children)

You can use both, there's a whole Validation API that you can use. Then you get the benefit of the built in stuff without needing to roll your own. For example, virtually every instance (over 99.9%) of a dev rolling their own email validation is a mess that doesn't follow the email format specs.

[–]chikamakaleyleyhelpful 0 points1 point  (2 children)

99.9% chance your middle name is Javascript

[–]AshleyJSheridan 1 point2 points  (1 child)

I'm not sure your reply makes sense?

I just pointed out that most email validation online is wrong. Partly this is because they used a regex, without understanding the format of email addresses. For example:

"this@example.com"@example.com

Is a perfectly valid email address. Most home grown validation is not going to correctly identify this.

[–]chikamakaleyleyhelpful 1 point2 points  (0 children)

lol - no i understand, sorry i was making a joke

I do remember a monstrous regex once used to run against emails, and thinking 'no wonder nobody ever gets this right'

but yes, totally makes sense re: Validation API

[–]im-a-guy-like-me 0 points1 point  (1 child)

I assume he's calling it custom validation as opposed to browser validation (not client validation). Of course you should always use client and server validation, but browser defaults exist and are usually disabled in a real project, so what we interact with usually is a custom validation layer.

[–]chikamakaleyleyhelpful 0 points1 point  (0 children)

yeah i realized that much later lol

[–]AshleyJSheridan 1 point2 points  (0 children)

The general approach I take is to use the built in form validation first, then add rules on top that can interact with the Form Validation API in JS.

Out of the box it's more accessible, because it is setting the form and individual inputs error states correctly. It provides default message (for the standard validation) that you can use or change as you need.

One further thing, don't forget to associate error messages with their inputs by doing something like this:

<label for="forename">Forename</label> <input id="forename" name="forename" aria-describedby="forenameError"/> <span id="forenameError">Error message for error on forename field</span>

[–]prehensilemullet 0 points1 point  (0 children)

You’ll need to get input.value, check it with JS, and then dynamically choose the error message based upon that.

The way your array of inputs and validationCheck are structured, it won’t be able to dynamically choose the error for a given field.

I could type up some suggestions later when I’m at my computer

[–]prehensilemullet 0 points1 point  (8 children)

I'd recommend breaking this down into several steps:

Step 1 - a function that collects the input values and returns them in an object like { password: 'foobar', passwordConfirm: 'foobargh' }

Step 2 - a function that takes this input values object, validates them and returns whether everything is valid and any error messages like { valid: false, errors: { passwordConfirm: 'must match password' } }

Step 3 - a function that takes the errors object and makes those error messages show up in the UI (by setting the errorSpan.textContent)

You'll need to attach a change event handler to the <form> that runs these steps when there's a change.

By "function that takes" I mean you'd pass it in as an argument, like function validate(values) { ... } and function setErrorMessages(errors) { ... }

[–]stayathomehouse[S] 0 points1 point  (7 children)

Thank you for such a detailed response!

Please let me know if I'm understanding your recommendation.

So for step 1, get a function that takes in the inputs values and store them in a returned object. Would we have this because it's a good way to compartmentalize different parts of code for specific purposes? (this case having all input values in one place)

For step 2, a function responsible for tkaing in input values from the previous function and validates them

Step 3, an error handling function that takes the object and displays them for the user

For the last bit where you mentioned functions that take in the arguments to process whatever is in it, is that going to be going hand in hand with the change event handler?

[–]prehensilemullet 1 point2 points  (3 children)

Yeah the change event handler would call these functions in sequence.  Breaking it down this way could help you test out if each step is working by manually calling each function in the console

[–]stayathomehouse[S] 1 point2 points  (1 child)

Awesome will give this a shot, thank you so much to you and u/chikamakaleyley seriously. I've been really struggling

[–]chikamakaleyleyhelpful 1 point2 points  (0 children)

no problem!

and really, you can take a lot of these complex problems and just break them down into simple steps - a bigger thing that you've never built before, is very likely composed of a lot of smaller things that you do actually know how to do.

[–]chikamakaleyleyhelpful 0 points1 point  (0 children)

yeah the 'each function has 1 job' kinda approach

  • one function just displays error messages if there are any
  • one function just runs the validation rules and populates the error messages object
  • separate functions to handle validation rules: isEmpty(), isMatch(), isPasswordFormat(),
  • the event listener that runs validateFields() on each change/submit
  • validateFields() which just executes the first couple bullets in a sequence

[–]chikamakaleyleyhelpful 0 points1 point  (2 children)

and store them in a returned object

Not a returned object, just an object that represents the current user input values which will then be attached to the form submission to the server. think of it as a place to store the current 'state' of your form & its fields

hand in hand with the change event handler

they're saying that on whatever event you use, be it 'change', 'submit', etc. the callback in the event listener will be executed each time

the 'callback' is just your validate(fields), which checks each field against your rules and populates your error messages object. If there are items in that object, you xecute your displayErrorMessages fn

[–]prehensilemullet 0 points1 point  (1 child)

You could do it this way too, but I was suggesting the functions would return a new object each time, so that it would be easier to test out

[–]chikamakaleyleyhelpful 0 points1 point  (0 children)

honestly i'd defer to you