Skip to content

Instantly share code, notes, and snippets.

@isralduke
Created January 15, 2016 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save isralduke/d75194b1d02d90ce4ef6 to your computer and use it in GitHub Desktop.
Save isralduke/d75194b1d02d90ce4ef6 to your computer and use it in GitHub Desktop.
Raven + AJAX + Happy JS Validation
{{ raven:form formset="contact" attr="id:contact-form|class:contact-form" }}
<div class="row">
<div class="col-xs-12 col-sm-4">
<div class="form-group">
<label for="">{{ theme:partial src="reqd" }} Name</label>
<input type="text" class="form-control" name="name" id="name" placeholder="What is your name?">
</div>
</div>
<div class="col-xs-12 col-sm-4">
<div class="form-group">
<label for="">{{ theme:partial src="reqd" }} Email</label>
<input type="email" class="form-control" name="email" id="email" placeholder="What is your email address?">
</div>
</div>
<div class="col-xs-12 col-sm-4">
<div class="form-group">
<label for="">{{ theme:partial src="reqd" }} Phone</label>
<input type="tel" class="form-control" name="phone" id="phone" placeholder="What is your phone number?">
</div>
</div>
<div class="col-xs-12 website">
<div class="form-group">
<label for="website">{{ theme:partial src="reqd" }} Website</label>
<input type="url" class="form-control" name="website" id="website" placeholder="What is your website url?">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-4">
<div class="form-group">
<label>Select a Location</label>
</div>
<div class="form-group">
<select class="form-control" name="location" id="location">
<option value="North Blvd">North Blvd</option>
<option value="Highland Road">Highland Road</option>
<option value="Silverside Drive">Silverside Drive</option>
<option value="Congress Drive">Congress Drive</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-6">
<div class="form-group">
<label for="">{{ theme:partial src="reqd" }} Message</label>
<textarea name="message" id="message" cols="30" rows="10" class="form-control" placeholder="What would you like to ask us?"></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-2">
<button class="btn btn-primary btn-block" type="submit" id="submit">Send</button>
</div>
</div>
{{ /raven:form }}
<div class="row">
<div class="col-xs-12 col-sm-4">
<p class="successMessage">
Thanks! We&rsquo;ll be in touch soon.
</p>
</div>
</div>
# Location (from root) to save form submissions
submission_save_path: _forms/contact/
# Fields allowed to be submitted in the form, automatically
# purging anything and everything else
allowed:
- name
- email
- phone
- location
- message
honeypot: website
# You are not required to require fields, but once you do, any missing
# from the POST will squash this submission and send a list of
# missing fields to your {{ raven:errors }} tagpair
required:
- name
- email
- message
submission_save_extension: yaml
# Configure notification email
email:
to: isral@stundesign.com
from: "{{ email }}"
subject: CDS Website Form Message
automagic: true
html_template: email
# text_template: text_email
datestamp_format: "Y F d"
control_panel:
fields:
- name
- email
- phone
- location
metrics:
-
type: count
field: email
label: Total Submissions Received
/*global $*/
(function happyJS($) {
$.fn.isHappy = function isHappy(config) {
var fields = [], item;
var pauseMessages = false;
function isFunction(obj) {
return typeof obj === 'function';
}
function defaultError(error) { //Default error template
var msgErrorClass = config.classes && config.classes.message || 'unhappyMessage';
return $('<span id="' + error.id + '" class="' + msgErrorClass + '" role="alert">' + error.message + '</span>');
}
function getError(error) { //Generate error html from either config or default
if (isFunction(config.errorTemplate)) {
return config.errorTemplate(error);
}
return defaultError(error);
}
function handleSubmit(e) {
var i, l;
var errors = false;
if (config.testMode) {
e.preventDefault();
}
for (i = 0, l = fields.length; i < l; i += 1) {
if (!fields[i].testValid(true)) {
errors = true;
}
}
if (errors) {
if (isFunction(config.unHappy)) config.unHappy(e);
return false;
} else if (config.testMode) {
if (window.console) console.warn('would have submitted');
if (isFunction(config.happy)) return config.happy(e);
}
if (isFunction(config.happy)) return config.happy(e);
}
function handleMouseUp() {
pauseMessages = false;
}
function handleMouseDown() {
pauseMessages = true;
}
function processField(opts, selector) {
var field = $(selector);
if (!field.length) return;
selector = field.prop('id') || field.prop('name').replace(['[',']'], '');
var error = {
message: opts.message || '',
id: selector + '_unhappy'
};
var errorEl = $(error.id).length > 0 ? $(error.id) : getError(error);
var handleBlur = function handleBlur() {
if (!pauseMessages) {
field.testValid();
} else {
$(window).one('mouseup', field.testValid);
}
};
fields.push(field);
field.testValid = function testValid(submit) {
var val, temp;
var required = field.prop('required') || opts.required;
var password = field.attr('type') === 'password';
var arg = isFunction(opts.arg) ? opts.arg() : opts.arg;
var errorTarget = (opts.errorTarget && $(opts.errorTarget)) || field;
var fieldErrorClass = config.classes && config.classes.field || 'unhappy';
var testResult = errorTarget.hasClass(fieldErrorClass);
var oldMessage = error.message;
// handle control groups (checkboxes, radio)
if (field.length > 1) {
val = [];
field.each(function(i,obj) {
val.push($(obj).val());
});
val = val.join(',');
} else {
// clean it or trim it
if (isFunction(opts.clean)) {
val = opts.clean(field.val());
} else if (!password && typeof opts.trim === 'undefined' || opts.trim) {
val = $.trim(field.val());
} else {
val = field.val();
}
// write it back to the field
field.val(val);
}
// check if we've got an error on our hands
if (submit === true && required === true) {
testResult = !val.length;
}
if ((val.length > 0 || required === 'sometimes') && opts.test) {
if (isFunction(opts.test)) {
testResult = opts.test(val, arg);
}
else if (typeof opts.test === 'object') {
$.each(opts.test, function (i, test) {
if (isFunction(test)) {
testResult = test(val, arg);
if (testResult !== true) {
return false;
}
}
});
}
if (testResult instanceof Error) {
error.message = testResult.message;
}
else {
testResult = !testResult;
error.message = opts.message || '';
}
}
// only rebuild the error if necessary
if (!oldMessage !== error.message) {
temp = getError(error);
errorEl.replaceWith(temp);
errorEl = temp;
}
if (testResult) {
errorTarget.addClass(fieldErrorClass).after(errorEl);
return false;
} else {
errorEl.remove();
errorTarget.removeClass(fieldErrorClass);
return true;
}
};
field.on(opts.when || config.when || 'blur', handleBlur);
}
for (item in config.fields) {
if (config.fields.hasOwnProperty(item)) {
processField(config.fields[item], item);
}
}
$(config.submitButton || this).on('mousedown', handleMouseDown);
$(window).on('mouseup', handleMouseUp);
if (config.submitButton) {
$(config.submitButton).click(handleSubmit);
} else {
this.on('submit', handleSubmit);
}
return this;
};
})(this.jQuery || this.Zepto);
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//malsup.github.com/min/jquery.form.min.js"></script>
{{ theme:js tag="true" src="bootstrap.min" }}
{{ theme:js tag="true" src="happy" }}
{{ theme:js tag="true" }}
$(document).ready(function() {
function formend() {
$('#contact-form').slideUp(350);
$("#contact-form")[0].reset();
$('.successMessage').slideDown(350);
}
$('#contact-form').isHappy(
{
fields: {
'#name': { required: true, message:'We need your name!'},
'#email': { required: true, message:'Give us your email!'},
'#phone': { required: true, message:'Can we have your phone number?'},
'#message': { required: true, message:'Be sure to send a message to us.'}
}
});
$('#submit').click(function() {
$('#contact-form').ajaxForm(function() {
formend();
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment