If client-side validation in QuickForm2 doesn't work, you probably did not include the file it depends upon.
While HTML_QuickForm implemented client-side validation and provided several Javascript-backed elements, support for Javascript there was quite limited. Basically, all scripts were inlined and there were some rudimentary checks to prevent outputting the same (library) code twice.
This was addressed in HTML_QuickForm2, Javascript handled by the package is logically split into several parts:
A page containing two Javascript-backed forms will look like this:
...
[JS libraries used by form1 and form2]
...
[form1 html, including inline javascript]
[form1 setup code]
...
[form2 html, including inline javascript]
[form2 setup code]
...
An instance of HTML_QuickForm2_JavascriptBuilder takes care of libraries and setup code, inline code can be added using HTML_QuickForm2_Element_Script element.
The new approach allows keeping the code that does not change (libraries) in external
*.js
files, instead of bloating the resultant HTML. If form's structure does
not change either, generated form setup code may also be moved to an external file. Only code
that changes from one request to the other (e.g. setting the element's value) has to be inlined.
HTML_QuickForm2_JavascriptBuilder is used together with renderers. Form Javascript is generated in the course of HTML_QuickForm2::render() call, so that call is mandatory if you are using Javascript in your form.
Javascript library files are registered via addLibrary(). You will
only need to call this directly if you create custom Elements or Rules or maybe want to override validation
behaviour. Correct $webPath
and
$absPath
need to be provided so that later call to getLibraries() can
generate both links to external files and inline code.
Form setup code usually contains client-side validation rules added with addRule() and element
setup code added with addElementJavascript(),
the latter dealing with event handlers necessary for element behaviour. For example, built-in
Hierselect element adds
onchange
handlers for contained selects, onreset
handler
for a containing form and onload
handler for window
. Once
again, you will only directly call addElementJavascript() if you are creating
a custom element or want to add some custom setup code. You don't need to call
addRule() at all, as it is done automatically if you added a Rule to an
Element with HTML_QuickForm2_Rule::CLIENT flag set. Javascript added by
these two methods is later returned by getFormJavascript()
method which is usually called automatically by a renderer. It is also possible to use separate
getSetupCode() and
getValidator()
methods.
HTML_QuickForm2_JavascriptBuilder also contains a static helper method
encode() which encodes a
PHP value as a Javascript literal. This is similar to json_encode(), but does not
enforce UTF-8
charset.
There are currently three library files installed with the package:
quickform.js
quickform-hierselect.js
quickform-repeat.js
Human-readable versions of these files are installed into HTML_QuickForm2/js
directory under PEAR's
data_dir
and minified versions are installed into HTML_QuickForm2/js/min
. If you have trouble finding where
data_dir
is, you can use config-show command of PEAR installer.
While form setup code and inline Javascript is automatically added to output when rendering a form, libraries are not added automatically. The main reasons for this are
<head></head>
section of HTML document, while renderer outputs only the form itself.
<script
src="..."></script>
tags referencing installed
*.js
files. Inlining the code works for package examples but leads to
useless bloat in most other circumstances.
Libraries should be added to a page before outputting forms and definitely before outputting form setup code. Both inline scripts and form setup code can contain calls to library functions and changes to library properties.
It is possible to just copy *.js
files from PEAR's
data_dir
to a directory accessible via HTTP and manually add necessary
<script src="..."></script>
tags to the page. You will
however need to manually update this list if you decide to use a new Element or a new Rule which
requires an additional Javascript file. A better approach is to let
HTML_QuickForm2_JavascriptBuilder keep track of the used libraries and
rely on its getLibraries() method to include them.
There are two ways to include the library code in your page using HTML_QuickForm2_JavascriptBuilder::getLibraries():
Inline the libraries, including their contents into the page
<?php
require_once 'HTML/QuickForm2/Renderer.php';
$renderer = HTML_QuickForm2_Renderer::factory('default');
$form->render($renderer);
echo $renderer->getJavascriptBuilder()->getLibraries(true, true);
echo $renderer;
?>
This is the approach taken by package example files as it is guaranteed to work with no
additional steps required from the user. It may also be useful while developing new
package-related *.js
files as you won't have problems with browser caching
them.
Copy/symlink *.js
files installed with the package to some directory under
your website's document root and provide this information to JavascriptBuilder:
<?php
require_once 'HTML/QuickForm2/Renderer.php';
require_once 'HTML/QuickForm2/JavascriptBuilder.php';
$renderer = HTML_QuickForm2_Renderer::factory('default');
// Here '/path/to/libraries' is whatever directory available via HTTP you copied libraries to
$renderer->setJavascriptBuilder(new HTML_QuickForm2_JavascriptBuilder('/path/to/libraries'));
$form->render($renderer);
// This will output necessary <script src="/path/to/libraries/..."></script> tags
foreach ($renderer->getJavascriptBuilder()->getLibraries() as $link) {
echo $link . "\n";
}
echo $renderer;
?>
The latter approach is obviously recommended for production use.
If your page contains several forms, you'll only need to have one set of libraries for them. Use the same instance of HTML_QuickForm2_JavascriptBuilder when rendering all forms.
dualselect.php
example shows among other things how to create a custom element with an additional JS library.
Form setup code is returned by HTML_QuickForm2_JavascriptBuilder::getFormJavascript(). This method is automatically called by built-in Renderers and thus the code is included in their output.
Note that HTML_QuickForm2's Javascript library does not use
DOMContentLoaded
event like jQuery and similar libraries
do:
$(document).ready(function() { // some code that will be run when complete DOM tree is built });
Instead, form setup code is run immediately and should be output after the form, when form's DOM tree is already available.