Due to human error, human incomprehension, or simple ignorance, people sometimes input
the incorrect state. Every application needs to implement data validation so you can know if
the data is a valid state.
Problem
Validation is not just a data entry problem it can also be a programmer problem. For example,
a human could enter the data correctly, but the code could perform some invalid operations
resulting in state corruption. You need to ensure that the validation occurs successfully.
Theory
Validation in an Ajax application means that the client or server can validate the data.
The validation to check if a valid number has been entered can be performed on either
the client side or the server side. Imagining the validation is performed on the client side, you
can define the following points:
• You use JavaScript to implement all validation.
• The client can act and validate before submitting the data to the server, thereby saving
a round trip to the server.
• The Web client is considered insecure, so the server could receive invalid data if clientside
validation is the only validation.
Client-side validation saves processing power on the server side by doing the validation
and using the resources of the client. The downside is that in an HTML application, the client
is considered insecure, and hackers can always bypass the security efforts of aWeb developer.
You can minimize the problems, but you cannot eliminate the problems.
In contrast, let’s look at server-side validation, where you can define the following points:
• You can implement all validation in the language of choice, whether that’s Java, C#,
C++, PHP, or Ruby.
• Server-side validation requires a round trip between the client and the server, which
wastes network resources.
• Server-side validation is considered secure, because you can use a firewall to control
access to the server-side resource.
Client-side validation is the preferred route from a performance perspective, and serverside
validation is the preferred route from a security perspective. However, you want both the
best performance and the best security, which seems impossible.
You must choose between performance and security. No magic trick gives you both without
any disadvantages. If you were to use a compiled application instead of aWeb client, you’d
still have the same problems. Even if your compiled client application were to use encryption,
you’d still have security problems. And if you have security problems, then you have validation
problems, so client-side validation must be considered insecure.
Having established that you cannot ensure the validity of the data from a security perspective,
you need to consider whether you need the performance or the partial security.
If a hacker were to present invalid data, then the calculation
would not work, and the server would generate an error. If the server is presented with
invalid data, under no circumstance should the invalid data cause the server to generate
a general protection fault (GPF).
You need to distinguish validation for system correctness from validation for application
correctness. When data has been verified for system correctness, it means that the data is correct,
but it might not make sense. When data has been verified for application correctness, it
means that the data is correct and makes sense. Most developers focus on application data
validation and not system data validation, partly because application data validation implies
system data validation. However, by mixing the two validations, you can miss many system
validation scenarios.
Consider this example, which illustrates the problems of mixing different validations:
In a quest to provide the best security, a well-known online Web mail provider implements
a server-side validation tool to filter email for malicious JavaScript statements. Without the filter,
users could inadvertently display an email that could act as a Trojan or a virus. However,
a hacker manages to fool the filter with the following code:
<img
src='http://server/image.gif'
target=""onload="javascript that uses single quotes and just goes on and on">
In the example source, the HTML tag img has an src attribute, but also a target and an
onload attribute. From a system-level perspective, this means there are three attributes. The
problem with the server filter is that it treats the target and onload attributes as one attribute.
This probably occurs because an application-level validation filter was created that didn’t
verify the data at the system level. Had the validation routines performed both a system-level
validation and an application-level validation, the error most likely would have been caught.
State and validation are not a simple problem. State and validation involve both a client
side and a server side, and involve both system-level validation and application-level validation.
In the proposed validation architecture, one problem remains: The client is considered
insecure, but the server expects that the client will send the right data. This could be a article
for disaster, but not because of how application validation is implemented. With most technical
implementations, application validation implies system-level validation.
The client fixes up the data so that errors are already removed. The server
side assumes that the data is correct, but still has the capability to catch errors if they occur.
Solution
To start, let’s look at the HTML page used to add two numbers together.
Source: /website/ROOT/ajax articles/dhtml/validation/test.html
<html>
<head>
<title>Validation Example</title>
<script language="JavaScript" src="/scripts/jaxson/common.js"></script>
<script language="JavaScript" src="/scripts/jaxson/converter.js"></script>
</head>
<body>
<form id="calculator">
<table border="1">
<tr>
<td>Number 1</td><td><input type="text" name="Number1" /></td>
</tr>
<tr>
<td>Number 2</td><td><input type="text" name="Number2" /></td>
</tr>
<tr>
<td>Result</td><td><span id="result"></span></td>
</tr>
<tr>
<td colspan="2">
<center>
<input type="button" value="Add the two numbers" onclick=""/>
</center>
</td>
</tr>
</table>
</form>
</body></html>
Notice that the form HTML element defines only the id attribute and not the method and
action attributes. This is done on purpose, as you’ll see in the article “Don’t Submit Your
Forms Ajax Them” presented in Article 8. The form uses standard form elements, such as
the input button and the input text box. The purpose of the form HTML element is to define
a block that contains all of the elements and represents a valid state. In the example, the valid
elements include the fields Number1 and Number2. The form block contains a span element that
represents the result of the addition.
When submitting forms using the browser-based HTML POST, you’re sending all of the
form elements (such as Number1 and Number2) to the server. When the POST returns, the result
returns. In the example HTML, the result is a span element, which is assigned by JavaScript.
Imagine if the result element were an HTML form; using an HTML POST would cause the result
to be sent to the server. Sending the state of the result is incorrect, because you’re sending output
data in an input state. The form example illustrates that there are multiple states and
multiple representations of the state. You separate the input state and output state using multiple
representations, which is the basis of the Representation Morphing pattern.1
The Representation Morphing pattern solves the problem
by associating the state methods with the HTML blocks. In the code example, that means
associating state methods to the form and to the span element.
Another solution is to create the global functions GetState and SetState but associate
identifiers with the global functions. These global functions are responsible for retrieving or
assigning the state with the representation. The advantage of this approach is that you have
a centralized location that you can extend or maintain.
Going back to the first code segment of this article, adding the global functions GetState
and SetState results in the following code.
Source: /website/ROOT/ajax articles/dhtml/validation/test.html
<html>
<head>
<title>Validation Example</title>
<script language="JavaScript" src="/scripts/jaxson/common.js"></script>
<script language="JavaScript" src="/scripts/jaxson/converter.js"></script>
</head>
<script language="JavaScript" type="text/javascript">
function GetState(identifier, cb) {
}
function SetState(identifier, obj, cb) {
}
</script>
<body>
<form id="calculator">
<table border="1">
<tr>
<td>Number 1</td><td><input type="text" name="Number1" /></td>
</tr>
<tr>
<td>Number 2</td><td><input type="text" name="Number2" /></td>
</tr>
<tr>
<td>Result</td><td><span id="result"></span></td>
</tr>
<tr>
<td colspan="2">
<center>
<input type="button" value="Add the two numbers" onclick=""/>
</center>
</td>
</tr>
</table>
</form>
</body></html>
The modified code, shown in bold in the updated HTML page, illustrates the definition of
the functions. The functions GetState and SetState provide the base infrastructure used to
retrieve and assign state to a representation. This means that GetState and SetState don’t
include functionality to make Ajax requests.
The function GetState has two parameters: identifier and cb. The identifier parameter
is the identifier of the representation to extract the state from.
The second parameter
cb is a callback function that is called to indicate an error or retrieved state. The second
parameter is a code block, as defined in Article 2. The reason for using a code block relates to
the multifunctionality of the GetState or SetState function. More about this will be discussed
in a moment.
SetState has a similar declaration to GetState, except that it includes an additional
parameter obj. The parameter obj is an object that is a state that will be assigned to the representation.
It is assumed that the representation knows about the data members defined by the
variable obj.
In the Representation Morphing pattern, the GetState and SetState functions are used to
assign and extract a state from a representation. The Representation Morphing pattern focuses
on the ability to serialize a representation, decouple a state from the representation, and serialize
the state when the representation is serialized. For this article, there is the additional
requirement to perform validation. From a programmatic perspective, adding validation is
straightforward. What makes validation more complicated is the additional interaction aspects.
For example, what would the application do if a validation failed? Should it display a dialog
box or a blinking message? If a validation error occurs, should the application show the first
error and stop validating?
Let’s focus on the extraction of the state using the function GetState. You must implement
the following details when using GetState:
• When extracting the state for the numbers, you must reference the text box value
properties for Number1 and Number2.
• When extracting the state for the result, you must reference the span innerHTML property.
• You must validate the text box values Number1 and Number2 as being numbers.
• If the validation fails, you must generate and display an error so users can take corrective
action.
• You must not display errors on a piecemeal basis. The validation routines must go
through the entire state and generate errors for everything found.
• When no more validation errors occur, pass the generated state to the caller. Note that
multiple state instances might occur.
You should notice the generation of multiple errors or multiple state instances. Whenever
an algorithm is confronted with multiple results, the results are stored temporarily in an array
that is processed by the caller of the algorithm. As shown in Article 2’s code block article, you
could also use code blocks. Code blocks would be the appropriate choice, because there may
or may not be errors, and there may or may not be a state instance.
To illustrate the complexities, consider the following code, which illustrates each
approach of calling the GetState function:
function GenerateState() {
var noErrors = true;
var result = GetState( "identifier");
for( int c1 = 0; c1 < result.errors.length; c1 ++) {
// Do something with error
noErrors = false;
}
if( noErrors == true) {
for( int c1 = 0; c1 < results.state.length; c1 ++) {
// Do something with the results
}
}
}
The first line is an assignment of the variable noErrors. The variable noErrors is used to
indicate whether errors occur when extracting the state. If there are errors, then processing
the state would be silly since there is no state or if there is, it is incomplete.
Calling the function GetState returns an object instance, which has two data members:
errors and state. The two data members are arrays that contain the errors and generated
state instances. After the call to GetState, a loop iterates the validation errors and, if necessary,
generates a response. If an error is generated, the variable noErrors is assigned a value of false,
indicating an error. If there are no errors, the generated state instances are iterated.
As GetState is coded, the function is called and processes the state. If an error occurs,
then the caller of GetState needs to dissect what went wrong and how to indicate the errors
to the caller. Another solution is to use code blocks that simplify how the state or errors are
processed. Code blocks simplify the code, because they allow you to focus on adding value
with respect to code. The following code illustrates how a version of GetState uses code
blocks:
function GenerateState() {
GetState( "Identifier", {
error : function( errorItem) {
// Do something with error
}
state : function( stateInstance) {
// Do something with results
}
});
}
In the modified implementation of GenerateState, the GetState function is passed an
object instance that has two methods: error and state. Whenever an error occurs, the
function error is called. If no errors occur, then the function state is called. The caller of
GenerateState has a simplified implementation, because it only needs to take care of the cases
when an error or a state instance occur. If the caller doesn’t provide an implementation for the
function error, then any errors that would occur are ignored, and the caller only waits for a valid
state instance. The details of SetState and how to use it are similar to GetState. The difference
with SetState is that a state is being assigned to a representation.
Now let’s look at the implementation details of the HTML form again, as one additional
change has not yet been discussed, and it needs to be covered before discussing the details of
GetState or SetState:
<form id="calculator">
<table border="1">
<tr>
<td>Number 1</td><td><input type="text" name="Number1" />
<br><span id="Number1Error"></span></td>
</tr>
<tr>
<td>Number 2</td><td><input type="text" name="Number2" />
<br><span id="Number2Error"></span></td>
</tr>
<tr>
<td>Result</td><td><span id="result"></span>
<br><span id="resulterror"></span></td>
</tr>
<tr>
<td colspan="2">
<center>
<input type="button" value="Add the two numbers" onclick=""/>
</center>
</td>
</tr>
</table>
</form>
The bold text shows the addition of HTML span elements, which you use to display any
errors associated with the data. In past applications, you might have used a dialog box to indicate
errors. The problem with dialog boxes is that they talk about the problematic data but
don’t pinpoint it. With a fairly complex form, users might be left wondering where the error is.
Dynamic HTML (DHTML) gives you the ability to modify the HTML elements, thus making
the need to use a dialog box unnecessary.
This article uses an HTML span element that contains the error. You can use whatever you
want in your applications. Maybe you want to use blinking text, or maybe you want to change
fonts it’s your choice. It’s important, though, that you associate the error with the local
HTML element.
Now let’s cover the details of GetState, which can be a bit lengthy:
function GetState(identifier, cb) {
if (identifier == "toadd") { // 1
var form = document.getElementById("calculator");
document.getElementById("Number1Error").innerHTML = ""; // 2
document.getElementById("Number2Error").innerHTML = "";
var obj = new Object(); // 3
var didError = false; // 4
try {
obj.Number1 = Converter.convertToInteger(form.Number1.value); // 5
}
catch( e) {
didError = true;
document.getElementById("Number1Error").innerHTML = e.toString();
if (cb.error) {
cb.error({ section : "toadd",
item: "Number1", error : e.toString()}); // 6
}
}
try {
obj.Number2 = Converter.convertToInteger(form.Number2.value);
}
catch( e) {
didError = true;
document.getElementById("Number2Error").innerHTML = e.toString();
if (cb.error) {
cb.error({section: "toadd", item: "Number2", error: e.toString()});
}
}
if (cb.state && !didError) {
cb.state({ section: "toadd", value : obj}); // 7
}
}
else if (identifier == "result") {
var element = Navigation.findChild("calculator", "result");
Navigation.findChild("calculator", "resulterror").innerHTML = "";
var obj = new Object();
try {
obj.Result = Converter.convertToInteger(element.innerHTML);
}
catch( e) {
Navigation.findChild("calculator", "resulterror").innerHTML =
e.toString();
if (cb.error) {
cb.error({section: "Result",
item : "Result", error: e.toString()});
}
return;
}
if (cb.state) {
cb.state({ section : "result", value : obj});
}
}
else {
if (cb.error) {
cb.error({section: identifier,
error: "State identifier (" + identifier + "does not exist"});
}
}
}
The code is not complicated but lengthy, because the task you need to accomplish is
lengthy. The following list explains each of the bold lines of code. The numbers in the list
correspond to the numbers in the comments displayed in the highlighted code:
1. GetState makes a decision to determine which representation should be converted
into a state.
2. GetState resets the error messages associated with the representation. In this article,
that means assigning the innerHTML property of the individual HTML span elements to
an empty buffer. In your application, that might mean the resetting the blinking text or
changing the text font. It’s important to reset the error state so that no old errors are
displayed as the validation is being executed.
3. GetState instantiates an object using the Object type. The instantiation and use of the
Object type has a purpose. You might be tempted to instantiate a type that has predefined
data members and methods, but that is not advised. Imagine using DHTML and
generating a form dynamically. It could be that one context of the generated form has
a data member, and another context does not. From a state perspective, you want to
know the state that reflects the context, not what you think the context should be. Thus,
when you instantiate an Object that has no data members and you assign the data
members dynamically, you’re ensuring only that the data associated with the context is
present.
4. The variable didError is a flag that indicates whether a validation error occurred. This
flag is highlighted here to cross-reference the previous discussion regarding the reason
of using callbacks and not loops. The illustration of didError shows that the GetState
algorithm needs to track whether an error occurred.
5. Converter converts the HTML data into the requested type, which in the case of the
example is an integer value. The conversion is a function call that varies with the application
being written. The conversion includes a validation. Note that the conversion is
encapsulated within an exception block. The use of an exception block is preferred,
because all errors will be caught. The validation routines might miss some errors, but
the exception block can capture and display those errors.
6. If an exception is generated, the catch block captures the exception. Once the exception
has been captured, the user-defined error callback is called and can process the
error further.
7. If no errors are generated, the user-defined callback is called with the state of the form.
The code that is not bold is either a replication of the functionality or support code for
one of the seven details. Remember that the GetState and SetState functionalities are
self-contained. For example, when a validation fails and an error is generated, you have the
option of making the callback display the message. However, this approach isn’t desirable,
because the state code would have to know about the representation details. As per the Representation
Morphing pattern, it is not desirable to have the caller of GetState or SetState know
how the representations are implemented. This promotes a decoupling, just as the GetState and
SetState functions don’t know the origin of the data used to assign a state in a representation.
For illustration purposes, the following code displays the complete SetState functionality
and cross-references the details that implement the same functionality as the seven defined
details of the GetState function:
function SetState(identifier, obj, cb) {
if (identifier == "toadd") { // 1
var form = document.getElementById("calculator");
document.getElementById("Number1Error").innerHTML = ""; // 2
document.getElementById("Number2Error").innerHTML = "";
if (typeof(obj.Number1) != "number") { // 5
var buffer = "obj.Number1 expected a number, but is a " +
typeof(obj.Number1);
document.getElementById("Number1Error").innerHTML = buffer;
if (typeof(cb) != "undefined" && cb.error) {
cb.error({ section: "toadd", identifier : "Number1",
error : buffer}); // 6
}
}}
}
element.innerHTML = obj.Result;
}
else {
if (typeof(cb) != "undefined" && cb.error) {
cb.error({section: identifier,error: "State identifier (" + identifier +
"does not exist"});
}
}
When assigning the representation with a state, the same sort of logic is carried out, with
the exception of lines 3 and 7 from the previous code listing. Those numbers are not referenced
here, because when assigning a state, you’re passed the object instance that contains the state.
The server-side validation is not shown, because this article focuses on client-side solutions.
To complete the solution, you would use an Ajax request and send or receive the state
The server-side validation is not shown, because this article focuses on client-side solutions.
representation illustrates the state in a read-only mode. Using this article, you could retrieve
the state remotely, display it in read-only mode, edit it, and then send it back to the server.
Putting all of this together, you need to remember the following things about validation:
• Validation is not about validating some data. Validation first and foremost is about
defining a state that is associated with a representation. The purpose of validation is to
ensure that when state is transferred, the state is consistent.
• When performing validation, if the state is transferred to the server, then most likely the
client cannot be relied upon. The client is considered insecure, and therefore the most
you should expect is system-level validation that removes the “dumb” errors. This is not
to say that you cannot perform application-level validation just don’t put blind faith
into the validation if the application requires high security.
• When the client receives a state from the server, it doesn’t need to be validated, because
the server is considered secure. Metaphorically speaking, it is like going to a bank: the
bank teller doesn’t trust you and hence considers you, the individual, insecure. The inverse
is not true, as you do trust the teller and won’t question what the teller says or the monies
that you receive.
• When validating errors, you use DHTML to display an error near the location where it
occurred. For example, don’t generate a dialog box, because that can lead to cryptic
error messages.
• When implementing validation, use get state and set state functionality so that the
state, representation, and mechanisms used to transfer state can be decoupled from
each other.
• Use code blocks so that user functionality is called when necessary, decoupling the code.
|