Skip to content

Instantly share code, notes, and snippets.

@tinwatchman
Last active April 27, 2017 22:38
Show Gist options
  • Save tinwatchman/bf33baa6d086567576c8fd0c42e76df3 to your computer and use it in GitHub Desktop.
Save tinwatchman/bf33baa6d086567576c8fd0c42e76df3 to your computer and use it in GitHub Desktop.
A Knockout.js extension that adds Bootstrap form validation classes to a form group.
/**
* Knockout Extension: Bootstrap Form State
*
* Adds Bootstrap form validation classes to a form group; will also display
* a message if provided.
*
* @requires jQuery
* @requires Bootstrap 3
* @requires Knockout.js
*
* @author Jon Stout (www.jonstout.net)
*
* @example <caption>Basic usage</caption>
*
* Set up your markup along these lines:
*
* ```
* <form>
* <div class="form-group" data-bind="formState: observable">
* <label for="example">Example field</label>
* <input type="text" class="form-control" id="example">
* <span id="example-help" class="help-block" style="display:none;"></span>
* </div>
* </form>
* ```
*
* Then define an observable in your view model:
*
* ```
* this.observable = ko.observable();
* // set to false to clear the validation state
* this.observable(false);
* // set to a string to show an error message...
* this.observable('error message');
* // ... or set to an object with property `state` set to `"error"`
* this.observable({
* state: 'error'
* });
* // set to this to show a warning message:
* this.observable({
* state: 'warning',
* message: 'warning message'
* });
* // set to this to show success:
* this.observable({
* state: 'success',
* message: 'success!'
* });
* ```
*
* @example <caption>Markup for a horizontal form</caption>
*
* ```
* <form class="form-horizontal">
* <div class="form-group">
* <label for="example" class="control-label col-sm-2">Example field</label>
* <div class="col-sm-10">
* <input type="text" class="form-control" id="example">
* <span id="example-help" class="help-block" style="display:none">
* </span>
* </div>
* </div>
* </form>
* ```
*/
(function($, ko) {
if (typeof ko.bindingHandlers.formState === 'undefined') {
ko.bindingHandlers.formState = {
update: function(element, valueAccessor) {
/**
* Shows a message within a span.help-block inside of a form group, if
* one exists.
* @private
* @param {Element} formGroup Form group div
* @param {String} message Message to display
*/
var showMessage = function(formGroup, message) {
var help = $(formGroup).find('.help-block');
if (help.length > 0) {
help.html(message).show();
$(formGroup).find('input, select, textarea')
.attr('aria-describedby', help.attr('id'));
}
};
var val = ko.unwrap(valueAccessor());
if (typeof val === 'undefined' || val === null || !val) {
// if false or empty
$(element).removeClass('has-error')
.removeClass('has-warning')
.removeClass('has-success');
$(element).find('input, select, textarea')
.removeAttr('aria-describedby');
$(element).find('.help-block')
.empty()
.hide();
} else if (typeof val.state !== 'undefined' && val.state === 'success'){
// if success
$(element).addClass('has-success')
.removeClass('has-warning')
.removeClass('has-error');
if (typeof val.message !== 'undefined') {
showMessage(element, val.message);
}
} else if (typeof val.state !== 'undefined' && val.state === 'warning'){
// if warning
$(element).addClass('has-warning')
.removeClass('has-success')
.removeClass('has-error');
if (typeof val.message !== 'undefined') {
showMessage(element, val.message);
}
} else {
// if error
if (typeof val === 'String') {
showMessage(element, val);
} else if (typeof val.message !== 'undefined') {
showMessage(element, val.message);
}
$(element).addClass('has-error')
.removeClass('has-warning')
.removeClass('has-success');
$(element).find('input, select, textarea').focus();
}
}
};
}
})(jQuery, ko);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment