Control plugin architecture
formBuilder can be easily extended to support new controls. Rather than have all controls load into the core formRender.js file, bloating it with controls that are rarely used, less used controls can be added as a plugin.
Using a plugin
Adding a plugin control into your project is as simple as including the file in a <script>
tag in your page. Form data elements can now use this type & will be correctly rendered.
You should be able to easily determine what type (or subtype) is expected in your formData by the file naming scheme. starRating.js
indicates a control of type starRating
. Subtypes are delimited by a '.
'. So textarea.trymbowyg.js
has type textarea
, subtype trymbowyg
.
Example
<script src="dist/formRender.js"></script>
<script src="dist/control_plugins/starRating.js"></script>
<script type="text/javascript">
$('.form-output').formRender({
formData: `[
{
"type": "starRating",
"label": "Rating",
"name": "star-1492424082853"
}
]`,
dataType: 'json',
render: true
});
</script>
Creating a new control plugin
In general, to create a control in the formBuilder project, you will need to create a new class which inherits from the control
class (as defined in control.js
). When creating a plugin control, because this script will be executed in a different namespace, we need to instead define our new control in an array of functions to be run by the formRender class.
The window.fbControls
property is used to store any plugin control anonymous functions. Your function will receive a controlClass
argument which you can inherit from. It can also optionally receive an object containing all registered control
children classes with their type
as the object property/key, allowing you to create subtype classes which inherit from another control. Finally, your function should return the new class.
Compiling
formBuilder is written in ES6, but compiled back down to ES5 to ensure maximum browser support. This adds a layer of complexity in adding plugin control classes.
At the time of writing there are issues in getting gulp to compile plugin classes correctly using babel, therefore this needs to be done manually. Thankfully it is a relatively simple process:
- Write your new control in ES6, storing it in this directory as
yourClass.js
- Copy the entire contents of the file & paste in to https://babeljs.io/repl/.
- Copy the transpiled contents and save into a new file in this directory named
yourClass.es5.js
- Done!
New plugin example
src/js/control_plugins/starRating.js
// configure the class for runtime loading
if (!window.fbControls) window.fbControls = new Array();
window.fbControls.push(function (controlClass) {
/**
* Star rating class
*/
class controlStarRating extends controlClass {
configure() {
this.js = '//cdnjs.cloudflare.com/ajax/libs/rateYo/2.2.0/jquery.rateyo.min.js';
this.css = '//cdnjs.cloudflare.com/ajax/libs/rateYo/2.2.0/jquery.rateyo.min.css';
}
/**
* build a text DOM element, supporting other jquery text form-control's
* @return DOM Element to be injected into the form.
*/
build() {
return this.markup('span', null, {id: this.config.name});
}
onRender() {
let value = this.config.value || 3.6;
$('#'+this.config.name).rateYo({rating: value});
}
}
// register this control for the following types & text subtypes
controlClass.register('starRating', controlStarRating);
return controlRating;
});
Transpiled example
src/js/control_plugins/starRating.es5.js
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
if (!window.fbControls) window.fbControls = new Array();
window.fbControls.push(function (controlClass) {
/**
* Starz rating class
*/
var controlStarRating = function (_controlClass) {
_inherits(controlStarRating, _controlClass);
function controlStarRating() {
_classCallCheck(this, controlStarRating);
return _possibleConstructorReturn(this, (controlStarRating.__proto__ || Object.getPrototypeOf(controlStarRating)).apply(this, arguments));
}
_createClass(controlStarRating, [{
key: 'configure',
value: function configure() {
this.js = '//cdnjs.cloudflare.com/ajax/libs/rateYo/2.2.0/jquery.rateyo.min.js';
this.css = '//cdnjs.cloudflare.com/ajax/libs/rateYo/2.2.0/jquery.rateyo.min.css';
}
/**
* build a text DOM element, supporting other jquery text form-control's
* @return DOM Element to be injected into the form.
*/
}, {
key: 'build',
value: function build() {
return this.markup('span', null, { id: this.config.name });
}
}, {
key: 'onRender',
value: function onRender() {
var value = this.config.value || 3.6;
$('#' + this.config.name).rateYo({ rating: value });
}
}]);
return controlStarRating;
}(controlClass);
// register this control for the following types & text subtypes
controlClass.register('starRating', controlStarRating);
return controlStarRating;
});