Dynamic form widgets for Angular.
MacGyver is a form designer for Angular that works by being given a form definition and a data set.
angular
.module('macgyver')
.component('myComponent', {
controller: function() {
var $ctrl = this;
$ctrl.data = {}; // This will be populated by MacGyver
$ctrl.form = { // Our form specification
type: "mgContainer",
items: [
{
id: "textInput",
type: "mgText",
title: "Example Text",
},
{
id: "toggleControl",
type: "mgToggle",
default: true,
},
],
};
},
template: `
<mg-form config="$ctrl.form" data="$ctrl.data"></mg-form>
`,
});
MacGyver also ships with a form editor. To use simply make a HTML page with the mgFormEditor
component for an interactive UI.
<mg-form-editor config="$ctrl.form" data="$ctrl.data"></mg-form-editor>
MagGyver works by using Angular's template system to nest widgets with two-way data binding.
Each MagGyver widget begins with mg
and should be registered via $macgyver.register()
.
angular
.module('macgyver')
.config($macgyverProvider => $macgyverProvider.register('mgText', {
title: 'Textbox',
icon: 'fa fa-pencil-square-o',
config: {
placeholder: {type: 'mgText', help: 'Ghost text to display when the textbox has no value'},
},
}))
.component('mgText', {
bindings: {
config: '<', // Config for this widget
data: '=', // Data state for this widget
},
controller: function($macgyver, $scope) {
var $ctrl = this;
$macgyver.inject($scope, $ctrl);
// Adopt default if no data value is given
$scope.$watch('$ctrl.data', ()=> { if (_.isUndefined($ctrl.data) && _.has($ctrl, 'config.default')) $ctrl.data = $ctrl.config.default });
// Optionally respond to validation requests
$ctrl.validate = ()=> {
if ($ctrl.config.required && !$ctrl.data) return `${$ctrl.config.title} is required`;
};
},
template: `
<input ng-model="$ctrl.data" type="text" class="form-control" placeholder="{{$ctrl.config.placeholder}}"/>
`,
})
The main service / provider within Angular.
NOTE: $macgyverProvider
and $macgyver
are the same. The provider is available as an alias to allow registration of components during the Angular Config phase.
Register a widget for use by name. Each id should begin with id
and be in camelCase form.
Widgets can contain the following meta properties:
Property | Type | Default | Description |
---|---|---|---|
config |
Object |
none | Object detailing each optional property the widget can take as a mgContainer specification |
icon |
string |
none | The icon CSS class to use in the mgFormEditor UI |
isContainer |
boolean |
false |
Indicates that the widget can contain other widgets (under the items array) |
isContainerArray |
boolean |
false |
Addition to isContainer that indicates the widget will contain an array of rows (like a table) |
template |
string |
<COMPONENT_NAME/> |
Rendering template to be used to draw the element |
title |
string |
The ID via _.startCase() |
The human friendly title of the widget |
userPlaceable |
boolean |
false |
Whether to hide the object from the user in the mgFormEditor UI |
Finds and returns the component scope of the first available form under the given scope.
Function used by MacGyver components to register themselves against the standard event hooks during initialization.
Generate an empty data entity from a given widget container. This function can be used to return the 'blank' form contents. If useDefaults == true
the defaults for each widget will be set as the value.
Attempt to neaten up a 'rough' MacGyver spec into a pristine one. This function performs various sanity checks on nested elements e.g. checking each item has a valid ID and if not adding one.
Create an empty data structure based on the specification. This is really just used to make sure that the deeply nested objects-within-objects (or arrays) are present when Angular tries to bind to them.
An object containing data on each valid MacGyver widget registered. If running on the front-end this is updated as new widgets register themselves. On the backend this uses the computed version located in ./dist/widgets.json
.
MacGyver components are also expected to optionally respond to the following events:
Used by MacGyver to 'ping' controls. Each control is expected to populate the register object with its ID and $ctrl
instance.
This event is automatically responded to if the component calls $macgyver.inject()
during its init cycle. If the component does not respond higher-level events such as validation will not be able to reach the component.
Used by MacGyver during $macgyver.getForm()
calls to retrieve the forms under the scope.
The responding form is expected to populate the form.form
object with its controller instance.