Chapter 11. Forms and Validation: Say what you meant to say

image with no caption

Everyone makes mistakes from time to time.

Give a human being a chance to talk (or type) for a few minutes, and they’ll probably make at least one or two mistakes. So how do your web apps respond to those mistakes? You’ve got to validate your users’ input and react when that input has problems. But who does what? What should your web page do? What should your JavaScript do? And what’s the role of the server in validation and data integrity? Turn the page to answer all of these questions, and a lot more...

Marcy’s Yoga for Programmers... a booming new enterprise

With her hip new site and super-fast response times, Marcy’s Yoga for Programmers site has exploded. She’s got some of Silicon Valley’s highest-end clientele signing up daily. She’s even added online enrollment, so once a potential client finds the perfect class, they can sign up right away:

image with no caption
image with no caption

The owner of the page knows their requirements better than you do.

No matter how good of a programmer you are, you’re not an expert in your customer’s business. So you probably won’t always make good assumptions about things like required fields, the types of data that can be entered, or the format of that data.

Note

For Marcy’s site, Marcy is the customer, and you’re the programmer.

It’s best to come up with some basic ideas about validation, and then confirm and expand those ideas by talking to whomever actually owns the site or business that the site represents.

Validation should work from the web page BACK to the server

Validation is usually a multi-step process. Some things you can catch by using certain controls on your web page, like a select box instead of a text field. You can catch other things with your client-side JavaScript, like the format of an email field. And still other things might need to go to the server to get validated, like seeing if a username’s already taken.

The most effective way to handle multi-layered validation like this is to always validate as much as you can on the web page. Then, move to JavaScript, and validate as much as you can there. Finally, involve the server.

image with no caption

Nobody enjoys an error message that says, “Hey, you screwed that up. Try again.”

You can validate the FORMAT of data, and you can validate the CONTENT of data

We’ve been using the term validation pretty loosely. At the user’s browser, we might make sure that the user enters their first name and birthday. That’s one form of validation. At the server, we might make sure that the user’s username isn’t already taken. That’s another form of validation.

In the first case, you’re validating a data format. You might make sure that a username is at least six characters long, or that there’s a value for the first name field, or that an email address has an @ sign and a .com or .org in it. When you’re validating a data format, you’re usually working with client-side code.

Note

image with no caption

Validate the format of user data with JavaScript.

By using client-side code to validate data formats, you can let users know of problems quickly, without waiting on a server response.

Well-designed applications validate both the FORMAT and the CONTENT of user data.

Sometimes you’ve got to do more than just see how many characters a string is, or make sure an entry is really a month of the year. You may need to check data against your database to prevent duplicate entries, or run a computation that involves other programs on your network.

In those cases, you’re validating the content of user data. And that’s not something you can usually do at the client. You’ll need to send the data to your server, and let programs on the server check out the data for validity.

Note

image with no caption

Validate the content of user data on the server.

You’ll need your app’s business logic to see if the content of user data is acceptable. Use server-side programs to let users know of problems with what they’ve entered.

You need BOTH types of validation to keep bad data out of your apps and databases.

We need to validate the FORMAT of the data from Marcy’s enrollment page

Let’s take another look at what we need to do to validate Marcy’s page. For each field, we’re actually just validating the format of the data. That means we should be able to do pretty much everything we need using JavaScript:

image with no caption
image with no caption

Joe: Like checkFirstname() and checkLastname(), right?.

Jim: Right. Then we just register each event handler to the right field, and boom, we’re good to go.

Joe: Perfect. So let’s—

Frank: Hang on a second, guys. I’m not sure that’s such a good idea. Aren’t we doing the same checks on several different fields?

Jim: You mean like making sure a field has a non-empty value? Yeah, that’s... ummm... first name, last name, and email.

Frank: Right. But aren’t we going to be repeating code in each one of those event handlers if we’re doing the same checks for different fields?

Joe: You know, he’s right. So maybe we need to have utility functions, like fieldIsFilled(), and we can call those from each event handler. So checkFirstname() and checkLastname() could just call fieldIsFilled() to see if those fields are empty.

Jim: Oh, that is better. So come one, let’s get—

Frank: Wait a second. I still think we can do better. Why do we even need a checkFirstname() function?

Jim: Well, duh, that’s got to call all the utility functions.

Joe: Hey, hang on, I think I see what Frank’s getting at. What if we built the utilities to take in a field, and do their check?

Jim: But you’d still need something to call all the checks for each field. Like I said, checkFirstname(), or whatever...

Joe: But can’t you assign multiple handlers to a single field?

Frank: That’s it! So you could just assign each validation function to the field it applies to. Like this...

Don’t Repeat Yourself: DRY

One of the core principles in software design is called DRY: don’t repeat yourself. In other words, if you write a piece of code once, in one place, try to avoid writing that piece of code again in some other place.

When it comes to validation, that means we shouldn’t write code that checks to see if a field is empty in two (or more!) places. Let’s write one utility function, and then use that function over and over again:

image with no caption

Now you can assign this handler to several fields, for instance in an initPage() function:

image with no caption
image with no caption

Jim: What do you mean? I tried it out, everything works great.

Frank: But you’re only assigning a single event handler to each field, right?

Jim: Right. And we’ve got our utility function, addEventHandler(), ready for when we need to add more handlers. So I’m all ready to handle multiple browsers and that whole addEventListener/attachEvent thing.

Frank: But you’re using this in fieldIsFilled()...

Jim: Sure. What’s the big... oh. Once we use addEventHandler()

Frank: —this stops working. That’s the problem.

Code that doesn’t repeat itself is easier to change, maintain, and debug.

Always try and write DRY code!

Let’s build some more event handlers

fieldIsFilled() was pretty simple. Let’s go ahead and write code for the other event handlers we’ll need. We can build each just like fieldIsFilled(): using getActivatedObject(), we can figure out the activated object, and then validate the format of the field.

image with no caption
image with no caption
image with no caption
image with no caption

An alert() stops EVERYTHING... and users don’t like to stop.

Using an alert() is pretty heavy-handed. That little popup brings everything on the page to a crashing halt. Earlier, we used some icons to let the user know what’s going on. But there was a problem with that approach, especially if you try and apply it to what we’re doing with Marcy’s page.

Why doesn’t a simple approved or denied icon work for Marcy’s page? What would you do differently?

image with no caption

Jim: That makes sense. So for each error, we can just display a message related to that error. Like, “Please enter a first name” or “E-mails should be in the format [email protected]”.

Frank: Yeah. That seems a lot more user-friendly.

Joe: But that won’t be so easy—.

Frank: Right, you see it, don’t you?

Jim: What?

Joe: Well, we moved to generic handler functions. Those functions don’t know about which field they’re testing, so they won’t know what error message to display.

Frank: Yeah. We need some way to have a set of error messages associated with each field. And then figure out a way to look up the right error message.

Joe: What about the activated object? We’ve got that in our handlers, so what if we use the object to look up an error message?

Jim: Hey, I’ve got an idea. Can we just have some sort of name/value thing, where there’s a name of a field, and the value for that field is an error message?

Frank: I like that... I think that would work. So we lookup the error based on the name of the field, which we’ve got from the activated object.

Joe: But aren’t there multiple problems that can occur for each field? We need more than one error message per field.

Frank: Hmmm. So we need a key for each field, and then a set of errors and corresponding messages for that. Right?

Jim: How the heck do we do that in JavaScript?

RETURN of SON of JavaScript

In the last chapter, server-side programs used JSON to represent complex object structures. But JSON isn’t just for the server-side! Anytime you need to represent name-to-value mappings, JSON is a great solution:

image with no caption

The value of a property can be another JavaScript object

You’ve already seen properties have string values, integer values, and array values. But a property can also have another object as its value, again represented in JSON:

image with no caption

Let’s warn Marcy’s customers when there’s a problem with their entry

With a warnings object full of useful messages, we can add warnings to Marcy’s page. Here’s what we’ve got in each event handler validation function:

  1. The field, via an activated object, that we need to validate.

  2. A specific type of problem that occurred (for example, we know whether a field was empty or invalidly formatted).

Based on that information, here’s what we need to do in our warning:

  1. Figure out the parent node of the field that there’s a problem with.

  2. Create a new <p> and add it as a child of that field’s parent node.

  3. Look up the right warning, and add that warning as text to the new <p>, which will cause the browser to display the warning on the form..

Here’s a warn() function that handles this for Marcy’s form:

image with no caption

Brain Power

How can we figure out when all fields are valid, and it’s safe to allow users to click “Enroll”?

image with no caption

eval() is safe to use when you CONTROL the data you’re evaluating.

In Chapter 10, we were evaluating data from a server-side program. We didn’t write that program, and weren’t even able to look at the source code. That makes that code unsafe to evaluate. We just weren’t sure that the code would be valid JSON, and would be safe to run on a user’s browser.

But with the warnings variable, we created the code we’re evaluating. So there’s no danger. In fact, we can test things out, and if there is a problem, we just make a change to warnings. So it’s perfectly safe to run eval() on code you’re in control of.

image with no caption

If you don’t warn(), you have to unwarn()

There’s one big problem with Marcy’s enrollment page: how do we get rid of those error messages when there’s not a problem? Here’s what our error handlers look like right now:

image with no caption

IF there’s a warning, get rid of it

Let’s build an unwarn() function. The first part is pretty simple: for the field that’s passed in, we just need to see if there’s a warning. If so, we can get rid of the warning. If there’s not a warning, we don’t need to do anything:

image with no caption
image with no caption

Validation is hard, thankless work... and EVERY application needs validation.

Getting data right on a form is often boring, and takes a long time to get right. But, validation is incredibly important to most customers. Take Marcy: without good data, she can’t enroll people in classes, she can’t send out mailings, and she can’t get new business.

Multiply that by all the web apps that you’re getting paid to develop, and validation becomes critical. And while Marcy’s enrollment form isn’t making asynchronous requests, it’s still a web application that’s typical of the things you’ll have to work on as a web developer. Not many programmers can make a living only working on asynchronous requests.

So take the time to get validation on your pages right. Your customers will love you and their businesses will flourish... and that means more work, better paychecks, and less middle-of-the-night, “It’s broken!” calls.

Every application needs validation!

Duplicate data is a SERVER problem

The only problem we’ve got left is when someone enters in their information twice, like Susan Smith on the last page. But it’s going to take a server-side program to handle that sort of problem... the server would need to take an entry, and compare it with existing entries in Marcy’s customer database.

image with no caption

You could do this with an asynchronous request...

Suppose we build a server-side program to take a user’s information, and check Marcy’s customer database to see if that user already existed. We could request that program using an asynchronous request in our JavaScript. Then, once the server returned a response, we could let the user know that their data’s been accepted.

... but what’s the benefit?

The only problem is that there’s nothinig for the user to do while they’re waiting. We’re probably using at least their first name, last name, and email to check against the database, so at most, a user could keep entering in their birthdate and bio. But even those aren’t required fields...

It’s really better to let the server check the user’s information when the user tries to enroll, and issue an error then. Since duplicate users aren’t a huge problem right now, you’re better off saving a ton of extra code, and simply letting the server handle reporting a problem to the user.

Sometimes, it’s best to let the server handle problems synchronously.

Not every web app needs asynchronous requests and responses!

So we’re done now, right?

That’s right. We’ve handled all of Marcy’s validation problems, and she’s going to have her server-side guys take a look at preventing duplicate data. In fact, let’s see how Marcy likes her new enrollment page...

image with no caption
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.122.185