UNPKG

6.38 kBMarkdownView Raw
1MacGyver
2========
3Dynamic form widgets for Angular.
4
5MacGyver is a form designer for Angular that works by being given a form definition and a data set.
6
7[LIVE DEMO](https://momsfriendlydevco.github.io/macgyver)
8
9
10Example
11-------
12```javascript
13angular
14 .module('macgyver')
15 .component('myComponent', {
16 controller: function() {
17 var $ctrl = this;
18
19 $ctrl.data = {}; // This will be populated by MacGyver
20
21 $ctrl.form = { // Our form specification
22 type: "mgContainer",
23 items: [
24 {
25 id: "textInput",
26 type: "mgText",
27 title: "Example Text",
28 },
29 {
30 id: "toggleControl",
31 type: "mgToggle",
32 default: true,
33 },
34 ],
35 };
36 },
37 template: `
38 <mg-form config="$ctrl.form" data="$ctrl.data"></mg-form>
39 `,
40 });
41```
42
43Editing a form
44--------------
45MacGyver also ships with a form editor. To use simply make a HTML page with the `mgFormEditor` component for an interactive UI.
46
47```html
48<mg-form-editor config="$ctrl.form" data="$ctrl.data"></mg-form-editor>
49```
50
51
52
53API Methods
54===========
55MagGyver works by using Angular's template system to nest widgets with two-way data binding.
56
57
58Creating MacGyver widgets
59-------------------------
60Each MagGyver widget begins with `mg` and should be registered via `$macgyver.register()`.
61
62```javascript
63angular
64 .module('macgyver')
65 .config($macgyverProvider => $macgyverProvider.register('mgText', {
66 title: 'Textbox',
67 icon: 'fa fa-pencil-square-o',
68 config: {
69 placeholder: {type: 'mgText', help: 'Ghost text to display when the textbox has no value'},
70 },
71 }))
72 .component('mgText', {
73 bindings: {
74 config: '<', // Config for this widget
75 data: '=', // Data state for this widget
76 },
77 controller: function($macgyver, $scope) {
78 var $ctrl = this;
79 $macgyver.inject($scope, $ctrl);
80
81 // Adopt default if no data value is given
82 $scope.$watch('$ctrl.data', ()=> { if (_.isUndefined($ctrl.data) && _.has($ctrl, 'config.default')) $ctrl.data = $ctrl.config.default });
83
84 // Optionally respond to validation requests
85 $ctrl.validate = ()=> {
86 if ($ctrl.config.required && !$ctrl.data) return `${$ctrl.config.title} is required`;
87 };
88 },
89 template: `
90 <input ng-model="$ctrl.data" type="text" class="form-control" placeholder="{{$ctrl.config.placeholder}}"/>
91 `,
92 })
93```
94
95
96$macgyver
97---------
98The main service / provider within Angular.
99
100**NOTE:** `$macgyverProvider` and `$macgyver` are the same. The provider is available as an alias to allow registration of components during the Angular Config phase.
101
102
103$macgyver.register(id, [properties])
104------------------------------------
105Register a widget for use by name. Each id should begin with `id` and be in camelCase form.
106
107Widgets can contain the following meta properties:
108
109| Property | Type | Default | Description |
110|--------------------|-----------|----------------------------|--------------------------------------------------------------------------------------------------|
111| `config` | `Object` | *none* | Object detailing each optional property the widget can take as a `mgContainer` specification |
112| `icon` | `string` | *none* | The icon CSS class to use in the `mgFormEditor` UI |
113| `isContainer` | `boolean` | `false` | Indicates that the widget can contain other widgets (under the `items` array) |
114| `isContainerArray` | `boolean` | `false` | Addition to `isContainer` that indicates the widget will contain an array of rows (like a table) |
115| `template` | `string` | `<COMPONENT_NAME/>` | Rendering template to be used to draw the element |
116| `title` | `string` | The ID via `_.startCase()` | The human friendly title of the widget |
117| `userPlaceable` | `boolean` | `false` | Whether to hide the object from the user in the `mgFormEditor` UI |
118
119
120$macgyver.getForm($scope)
121-------------------------
122Finds and returns the component scope of the first available form under the given scope.
123
124
125$macgyver.inject($scope, $ctrl)
126-------------------------------
127Function used by MacGyver components to register themselves against the standard event hooks during initialization.
128
129
130$macgyver.getDataTree(root, [useDefaults=false])
131------------------------------------------------
132Generate 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.
133
134
135$macgyver.neatenSpec(spec)
136--------------------------
137Attempt to neaten up a 'rough' MacGyver spec into a pristine one.
138This function performs various sanity checks on nested elements e.g. checking each item has a valid ID and if not adding one.
139
140
141$macgyver.specDataPrototype(spec)
142---------------------------------
143Create 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.
144
145
146$macgyver.widgets
147-----------------
148An 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`.
149
150
151API Events
152==========
153MacGyver components are also expected to optionally respond to the following events:
154
155mg.get(event, register)
156-----------------------
157Used by MacGyver to 'ping' controls. Each control is expected to populate the register object with its ID and `$ctrl` instance.
158This 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.
159
160
161mg.getForm(event, form)
162-----------------------
163Used by MacGyver during `$macgyver.getForm()` calls to retrieve the forms under the scope.
164The responding form is expected to populate the `form.form` object with its controller instance.