Hello!
Have just come across AJAX forms' validation and tried some solutions for it, but finally came to this approach. It supports multiple forms on one page. Maybe somebody will find this useful or suggest better approach.
First, define 'is_ajax' in kfunctions.php:
Then make your form:
And add some simple JS (use your AJAX library):
Works in IE9+, both with JS enabled or disabled.
Be careful, <cms:abort> tag works on 1.4.5RC2 version or above!
We capture errors manually and get a string
f_name => error, f_phone => error,
Then use json_encode (works on PHP 5.2+) and apply appropriate Content-type (application/json).
Previously I used an approach of getting full-page html in result of AJAX and splitting the interesting part, but new <cms:abort> tag allows to minify traffic and get clear JSON with right content-type, thanks to KK!
Updated accordingly to KK post.
Update: I got a bug with sending e-mails using AJAX. Seems that sometimes <cms:abort> is breaking further code like e-mail sending. If you get the same problem, just double <cms:send_mail> in AJAX block like:
Have just come across AJAX forms' validation and tried some solutions for it, but finally came to this approach. It supports multiple forms on one page. Maybe somebody will find this useful or suggest better approach.
First, define 'is_ajax' in kfunctions.php:
- Code: Select all
if( !method_exists($TAGS, 'is_ajax') ) {
$FUNCS->register_tag( 'is_ajax', 'is_ajax_handler' );
}
function is_ajax_handler( $params, $node ){
if( !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])=='xmlhttprequest' ){
return '1';
}
return '0';
}
Then make your form:
- Code: Select all
<style>
.hidden {display:none}
</style>
<cms:form action='' method='post' anchor='1' class="form">
<cms:input type="text" name="f_name" required="1" class="<cms:if k_error_f_name> error</cms:if>" />
<cms:input type="text" name="f_phone" required="1" class="<cms:if k_error_f_phone> error</cms:if>" />
<cms:input type="submit" name="f_submit" />
<div class="f-success hidden">The form is sent!</div>
<cms:if k_success>
<div class="f-success">The form is sent!</div>
<cms:if "<cms:is_ajax/>"><cms:abort><cms:content_type 'application/json' />{}</cms:abort></cms:if>
<cms:send_mail from=k_email_from to=k_email_to subject='New message'>
<p><strong>Name:</strong> <cms:show frm_f_name /></p>
<p><strong>Phone:</strong> <cms:show frm_f_phone /></p>
</cms:send_mail>
</cms:if>
<cms:if k_error>
<cms:capture into='errorsString'>
<cms:if k_error_f_name>f_name => error,</cms:if>
<cms:if k_error_f_phone>f_phone => error,</cms:if>
</cms:capture>
<cms:if "<cms:is_ajax/>"><cms:abort><cms:content_type 'application/json' /><cms:php>echo json_encode([<cms:show errorsString />]);</cms:php></cms:abort></cms:if>
</cms:if>
</cms:form>
And add some simple JS (use your AJAX library):
- Code: Select all
<script>
( function( window ) {
'use strict';
function classReg( className ) {
return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
}
var hasClass, addClass, removeClass;
if ( 'classList' in document.documentElement ) {
hasClass = function( elem, c ) {
return elem.classList.contains( c );
};
addClass = function( elem, c ) {
elem.classList.add( c );
};
removeClass = function( elem, c ) {
elem.classList.remove( c );
};
}
else {
hasClass = function( elem, c ) {
return classReg( c ).test( elem.className );
};
addClass = function( elem, c ) {
if ( !hasClass( elem, c ) ) {
elem.className = elem.className + ' ' + c;
}
};
removeClass = function( elem, c ) {
elem.className = elem.className.replace( classReg( c ), ' ' );
};
}
function checkEmpty( obj ) {
for (var i in obj) { return false; } return true;
}
var utils = {
hasClass: hasClass,
addClass: addClass,
removeClass: removeClass,
checkEmpty: checkEmpty
};
window.utils = utils;
})( window );
function clearErrors(elems) {
if (typeof elems === 'object') {
for (var t = 0; t < elems.length; t++) {
utils.removeClass(elems[t], 'error');
}
}
}
function applyAjaxSubmit(form, successEl) {
form.onsubmit = function() {
var formData = {};
for (var t = 0; t < form.elements.length; t++) {
formData[form.elements[t].name] = form.elements[t].value;
}
reqwest({ // use your library ($.ajax for jQuery)
url: '',
method: 'post',
data: formData,
success: function (resp) {
clearErrors(form.elements);
if (!utils.checkEmpty(resp)) {
utils.addClass(successEl, 'hidden');
for (var error in resp) {
utils.addClass(form.querySelector('#' + error), 'error');
}
} else {
utils.removeClass(successEl, 'hidden');
}
}
});
return false;
};
}
applyAjaxSubmit(document.querySelector('.form'), document.querySelector('.f-success'));
</script>
Works in IE9+, both with JS enabled or disabled.
Be careful, <cms:abort> tag works on 1.4.5RC2 version or above!
We capture errors manually and get a string
f_name => error, f_phone => error,
Then use json_encode (works on PHP 5.2+) and apply appropriate Content-type (application/json).
Previously I used an approach of getting full-page html in result of AJAX and splitting the interesting part, but new <cms:abort> tag allows to minify traffic and get clear JSON with right content-type, thanks to KK!
Updated accordingly to KK post.
Update: I got a bug with sending e-mails using AJAX. Seems that sometimes <cms:abort> is breaking further code like e-mail sending. If you get the same problem, just double <cms:send_mail> in AJAX block like:
- Code: Select all
<cms:if "<cms:is_ajax/>"><cms:send_mail from=k_email_from to=k_email_to subject='New message'>
<p><strong>Name:</strong> <cms:show frm_f_name /></p>
<p><strong>Phone:</strong> <cms:show frm_f_phone /></p>
</cms:send_mail><cms:abort><cms:content_type 'application/json' />{}</cms:abort></cms:if>