
//line 141 original file to replace
array_push($this->formerrors,array('id'=>$field['id'],'errormsg'=>$this->vFs->erro));
//will be replaced with
$this->formerrors[$field['id']]=array('errormsg'=>$field['invalidvalue']);
This way we will have an associative array, where the key is the input name, and the content is the error message that we will define per each input element of the form.
Second retouch: adding error fields to the Form output
Now we will modify the method renderForm(): this is used to print out the html code of our form, and if the Form was submitted it will display error messages (if any).
First, we will replace the loop that is at line 457 with a more efficient one, accordingly to the previous modification.
//line 457 original file to replace
if (isset($_POST['submit'])){
foreach ($this->formerrors as $error) {
if ($error['id']==$field['id']){
echo(' class="fbfielderror"');
$fieldErrorFound = true;
break;
}
}
}
//will be replaced with
if (isset($this->formerrors[$field['id']])){
echo(' class="fbfielderror"');
$fieldErrorFound = true;
}
Now we will add the error message right under the input associated with the error. During normal submission, and JS not active, the Form Class will print the error messages per each of those. Instead during Ajax submission we will use the id of each error message container to set the innerHTML property with the error message dynamically.
//line 583 original file we add
if(isset($this->formerrors[$field['id']])){
echo ("\n\t\t\t".'<p class="error" id="errfld_'.$field['id'].'">'. $this->formerrors[$field['id']]['errormsg'] .'</p>');
}else{
echo ("\n\t\t\t".'<p class="error" style="display:none;" id="errfld_'.$field['id'].'"></p>');
}
Note that we create the id just adding a suffix to the field name ("errfld_"), and we will still always have unique ids, as each form input name must be unique too.
Now, how will the form class detect the submission type, ajax or standard? The easiest path is by adding an hidden input text, with a default value (say 0), when the JS is called to submit the form, the value will be dynamically changed to another one (say 1). So in the Form Class, when we read the POST values, if this input value is the default value, we know the request is standard, otherwise it is an Ajax request.
//line 613 original file we add
echo('<input id="is_ajax_req" name="is_ajax_req" type="hidden" value="0">'."\n");
Third retouch: the JS code
Let's prepare the JS code to submit the Ajax request and manage the response. For this we will use a method called printJsCode(), but first we need to get access to the Form in the DOM Tree by name or Id. This will be easy:
//line 406 original file to replace
echo('<form class="fbform" action="'.$_SERVER['PHP_SELF'].'" method="post" enctype="multipart/form-data">'."\n");
//will be replaced with
echo('<form class="fbform" id="'. $this->formname .'" action="'.$_SERVER['PHP_SELF'].'" method="post" enctype="multipart/form-data">'."\n");
And, as in any Ajax application, a classic loading message. About this, you can use hundreds of possibilities, we will just make a classic one: create an empty div that gets the ajax-loading class as defined in the CSS when the Ajax request is sent.
//line 614 original file we add
echo('<div id="l_'.$this->formname.'"></div>'."\n");
Now, as we said at the begninning, we suppose that the output from the Ajax request is a number and eventually the list of errors message per each field. To keep data managment simple without using proper XML code, we can just imagine to use a simple CSV-like format, structured as follows:
response code
fld_name_1|error_message_1
fld_name_2|error_message_2
So '\n' will be our row identifier, and '|' the column identifier. In this case, we will expect our error messages without '\n' nor '|' chars.
//line 620 original file we add
function printJsCode(){
?>
$('<?php echo $this->formname ?>').addEvent('submit', function(e) {
//stop the exection of the POST method, we will handle it only in JS
new Event(e).stop();
//to access the form object inside functions we need another var
var that=this;
//we will inform the Form Class that this is an Ajax request
$('is_ajax_req').value='1';
//clean up all previous error messages
//this loop is made with mootools by selecting all p tags inside the form
// with id starting by "errfld_". You can use different loops methods accordingly to the
// JS package you use
this.getElements('p[id^=errfld_]').each(function(elm, i){
elm.style.display="none";
elm.innerHTML="";
});
//show the loading status
var loading_msg = $('l_<?php echo $this->formname; ?>').addClass('ajax-loading');
//in mootools this will just POST the form using an Ajax request instead of HTML posting.
//again, change it accordingly to the JS package you use
this.send({ evalResponse: false,
onComplete: function(response) {
//hides the loading status
loading_msg.removeClass('ajax-loading');
//reset the input just for safety - in case the user disables later the JS execution client-side!
$('is_ajax_req').value='0';
if(response=="") return;
//parse the response if not empty
var rows=response.split("\n");
//the status code
if(rows[0]=="0"){
//great, the form is valid
//do your stuff - redirect, show an alert, ... and exit
window.location = "thanks.htm";
return;
}
if(rows[0]=="-1"){
//errors: we need to show them
for(i=1;i<rows.length;i++){
//split the message: the first part is the field name, the second is the error message
if(rows[i]!=""){
var fields=rows[i].split("|");
//show the error
$("errfld_"+fields[0]).innerHTML=fields[1];
$("errfld_"+fields[0]).style.display="";
}
}
}
}});
});
<?php
}
Only one thing remains: we need to modify the method checkSubmit(), so that when an Ajax request is sent, we return the response and exit. The response format is the one we described above.
//line 158 original file we add
//is this an Ajax request?
if(isset($_POST['is_ajax_req']) && $_POST['is_ajax_req']=='1'){
//form invalid!
echo "-1\n";
foreach ($this->formerrors as $key=>$error) {
echo "$key|$error[errormsg]\n";
}
//stop the execution of the code here
exit();
}
//line 161 original file we add
//is this an Ajax request?
if(isset($_POST['is_ajax_req']) && $_POST['is_ajax_req']=='1'){
//form valid!
echo "0\n";
exit();
}
A small class change not related to the Ajax system, but just to make it work smarter
//line 61 original file to replace
if (isset($_POST['submit'])&&isset($_POST['fbformname'])&&$_POST['fbformname']==$this->formname) {
//will be replaced with
if (isset($_POST['fbformname'])&&$_POST['fbformname']==$this->formname) {
Final considerations
As you can see, modfying the existing class is simple, we added a few lines of code to achieve a good functionality and we almost won't need to modify our Form Objects (the only extra method we need to call is printJsCode(), that actually can be even included in the form printing function). Keep in mind that this is a guideline, and this method can be improved more, for example in this solution we won't be able to add extra validation conditions, as once the method checkSubmit() is called, the code execution will end. But modifying it will be a breeze.
Moreover, we can use the same technique for any form class, as the skeleton is always very similar, with any JS helper.
I have included a package with the modified class exactly as written in this article, plus a base example to try it out.
Feel free to use the forum to discuss this article and to suggest ideas or further improvment.
Here you will find a sample class build as described in this article. There is also a fully working demo - just unppack the zip file in a folder of your server and open index.php! Have Fun!
No. |
Attachments |
Downloads |
|
|
1 |
PHP Form Class with Ajax validation Find attached a PHP Form Class with Unobtrusive Ajax validation. To run the demo, unpack in your server folder and run index.php Uploaded on: 2007-09-30 | 09:37 pm |
2387 |
|
Added by Roberto on September-29-2007, 7:38 am

2010-11-10 | 05:14 am
2009-08-06 | 06:25 pm
2008-06-05 | 02:22 pm
2008-01-09 | 11:12 am