( Please read this before considering using it)
Preamble
Before anything else: *DO NOT* trust this client-side javascript verification in your server-side programs ! You have to redo all the necessary verification tests before digesting the data the remote browser sent you. There are numerous reasons for this:
- the browser may not interpret this javascript properly, or at all, and send whatever the field may contain without passing the verfication tests
- the client may pretty well be something else than a browser: a web crowler, a script, whatever someone may find useful to interact with your server for any reason
- the user may be smart enough to manually post random data and bypass the browser checkpoint entirely
JavaScript client side verification *only* intend to make the end-user experience a little smoother by showing where errors are, and avoiding a page reload every time he mistyped something. If you assume that all clients need to support your fancy javascript, you can save you some work on the server by not providing the same level of error notification (just displaying a stupid "error were found" message for example), but this is the only concession you can really safely do on the server.
How to use it
HTML Declaration
Using the form validation feature consists here again of attaching a few user-defined attributes to INPUT elements, as the example below shows:
| HTML |
<input type="text" name="aField" |
|---|---|
| CSS |
INPUT.invalid |
| UI |
- mjscheck
- This string represents the constraints that the field value needs to obey for passing validation. This is better explained in the following paragraphs.
- mjslabel
- Associates an alternate name to the field, which intend to be more human readable than the html element's name. For example, we may prever to use "Your user identifier" to "userid" in notification message; this can be done via this attribute.
- mjshelp
- Associate a message which intend to explain how the value needs to be set. You can see this as a "human readable" representation of the constraints you expressed via the "mjscheck" attribute. This message complement the default error messages that the formval module may produce.
Field constraints
You can attach constraints to any form field via the "mjscheck" attribute. The value of this attribute is a list of constraints, separated by the '&' character:
| number (or num) | the field should contains a numeric data (integer or floating point). This also implies "trim". |
| integer (or int) | the field contains an integer. This also implies "trim". |
| signed | applied to numeric data, this allow the use of negative values |
| date | the field contains a date |
| alpha | the field contains alpha chars ([A-Za-z]) only |
| alnum | the field contains alpha or numeric chars ([A-Za-z0-9]) only |
| word | the field contains "word" characters, according to the regexp engine (equivalent to /^\w+$/, or /^[A-Za-z0-9_]+$/ if you prefer) |
| required | the field shall contain a value (can't be empty if you prefer) |
| trim | leading and trailing spaces will be removed from the value |
| uc | value will be transformed to its uppercase equivalent before validating |
| lc | value will be transformed to its lowercase equivalent before validating |
| minLength=<value> | set the minimum size of the value (in number of characters) |
| manLength=<value> | set the maximum size of the value |
| length=<min>...<max> | alias for "minLength=<min>&maxLength=<max>" |
| min=<value> | this will make sure that the field is greater than the given value |
| max=<value> | this will make sure that the value is less than the given value |
| range=<min>...<max> | alias for "min=<min>&max=<max>" |
| filter=[<chars>] | select which character is allowed: 'filter=[a-zA-Z0-0]' (this test is done prior 're') |
| re=/regexpr/ | you can test the value by matching against a regular expression. See detailes paragraph about expressions. |
| focus | the field is given focus when loading the page |
Important notes:
- support for date constraints require the load of the date.js module (an error will be shown if it's missing)
- the range contraints (min, max, etc) will behave according to their type (dates, numbers, strings)
- constraint names are case-insensitive (MIN=1 and Min=1 do the same thing)
- numeric values are unsigned by default (because we believe it's more commonly used)
Styling
When the form validation code detects a fields with invalid content, it attach the CSS class "invalid" to this element. From there, you can choose the rendering option which suits your needs. The example below renders invalid fields with a RED border, a pale red background and a solid border:
| HTML |
INPUT.invalid |
|---|---|
| UI | Some required field |
Automatic form buttons
It is a common practice in most GUI frontend to dynamically change the state of a button when the end user alter one of the editable field of the page/dialog/form. There is no such thing in web standards, hence this specific feature of mjslib which is demonstrated in the example above:| HTML |
... <input type="button" name="submit" mjstype="autoFormButton" value="Submit"> |
|---|---|
| UI |
When you set the "mjstype=autoformbutton" attribute to a button object, the library automatically attach the following behavior:
- when the page is loaded, we verify that all fields have their default value (the value which is sent within the page). This is not always the case because few browsers remember values you have filled before under special circumstances. Is a change is detected, automatic buttons are (left) enabled. Otherwise, they are disabled because there is nothing to submit or reset.
- when any of the form field is altered, automatic buttons are enabled, denoting the fact that you should validate your values at some point
- when a "reset" button is clicked, automatic buttons are disabled again because we are back in initial state with no change to send
Important notes
- disabled fields are *not* verified,
which makes possible the use of this feature with the "fieldgroup"
module
- you may want occasionaly to submit your
form data without validation. Let's say that your page contains
a list of items which you can increase by adding and removing items
and let's say that your implementation requires a server-side code
to perform the list management. In this case, the "add"
and "remove" buttons will have to bypass the form validation
to submit data, because the editing is not terminated yet and you
don't want to block a delete action because one field is invalid.
This can be done by calling the "mjs_submitWithoutValidation()"
function directly from the "onclick" callback of the button,
as demonstrated in this example:
CSS <input type="submit" name="del1" value="Delete" onClick="return mjs_submitWithoutValidation();"> ... <input type="submit" name="del2" value="Delete" onClick="return mjs_submitWithoutValidation();"> ... <input type="submit" name="add" value="Add Item" onClick="return mjs_submitWithoutValidation();"> ... <input type="submit" name="send" value="Submit Form Data">
UI
Extending the engine
Registration mecanism
The form validation engine is designed to be extended with more controls which may better fit your needs. The date.js module already uses this mecanism to register specific controls related to dates (you can get code example from there). Basically, you can add more "data types" via the registration mecanism, providing a function which the framework will call when it will need it at verification time. Note that type-insensitive tests, such as regular expression, trim and such will always been performed before your function is invoked.
mjs_registerConstraintType(typeName,checkFunc,constraints[,alias1,...,aliasn]);
This function registers a new data type to the form validation framework. 'name' identifies the data name. Any field wanting to bind to this type will be able to do so by simply doing this: mjscheck="typeName&...".
The second parameter is a "pointer" to a function, which will be called by the framework when a field of this type needs to be validated. This function will receive 3 parameters: the HTML element which is beeing verified, the constraints object that contains the parsed "mjscheck" attributes, and the value of the element (usually identical to "element.value", but you need to use the passed value instead).
After validating the value, your function should return true when the value is correct. When an error occured, your code should return false. You can also use the function"mjs_formValidationFailed(fmt,...)" to set an error message in the meantime.
mjs_formValidationFailed(fmt[,prms])
Example: the "color" type
The example below demonstrates the extension mecanism by creating a new data type named "color", which needs to be formated in any of the "#RRGGBB" or "rgb:rrr,ggg,bbb" format:
| JavaScript |
function checkColor(element,constraints,value) |
|---|---|
| HTML |
<input type="text" name="favColor" |
| UI |
Tips and traps
- read carefully details about validation processing: your callback will take place after value alteration and basic tests are processed.
- your verification callback will not be called when another type-insensitive test failed. Also, it will not be called either when the field value is empty, regardless the "required" flag, because your code would not be necessary to test an empty value.
- you can pass null instead of
a callback; this will let you customize an existing type. Example:
mjs_registerConstraintType("reqint",null,"required&int");
This statement will register the data type "reqint", which is a derivation of the "int" type with the "mandatory" attribute set (in other words, it's a simple shortcut for "int&required"). - you need to register your new types before the formval module get initialized. Refer to the into page of this collection for more info about module initialization.
Technical notes
How validation occurs
When the form validation is performed, the "formval" module goes through all element of this form that need value checking (in the registration order, which usually follows the document sequence), and for each of them:
- perform value alteration
If you specified a constraint that may change the value of a field (see: uc, lc, trim), this is where it appens. The field value is read, the transformation occurs and the modified value is stored in the field (beware, the browser will send this modified value on submit!) - perform type-insensitive tests
a few tests do not require specific processing according to the type of the value: regular expressions, word, required, len. - type specific tests
remaining checks take the type into account. For example, date comparizons will have little in common with number compazisons; hence the need for type-specific functions
If your field passes all those tests, it's considered valid and marked as such. If one test fails, the verification processing stops there and the error is handled in various (and configurable) ways:
- the CSS class of the faulty field is altered so that you can render it in specific way (red borders, whatever)
- an alert message shows that there is a problem with this field. This message can also contain a specific text that you can craft for this specific field (ex: "Your birth date needs to be set in the past")
- the focus is given to the faulty field, and its content is selected
JavaScript API
mjs_formVerify(form[,notify=false])
mjs_setFieldVerificationState(el,state)
mjs_enableFormVerification(flag)
mjs_submitWithoutValidation()