Skip to content

Commit d44d28b

Browse files
committed
Updated extending docs
Not finished yet, but it's a start
1 parent 20e943c commit d44d28b

File tree

2 files changed

+195
-4
lines changed

2 files changed

+195
-4
lines changed

docs/extending.md

Lines changed: 194 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,198 @@
11
Extending Schema Form
22
=====================
33

4-
Extending schema form with new form field via add-ons or changing to another CSS framework (a new
5-
decorator) is easy. But how you do it has changed recently due to "the new builder".
4+
Schema Form is designed to be easily extended. You can add your own custom fields or completely
5+
change the how the entire form is rendered.
66

7-
New documentation is in the works and will come soon.
7+
A custom field is called an **add-on** and you can find community add-ons listed over at
8+
[schemaform.io](http://schemaform.io).
9+
10+
To completely change how the entire field is rendered you need to create what we call a **decorator**.
11+
A decorator is actually a collection of add-ons that at least cover the basic field types
12+
that a schema can default to, but usually a lot more.
13+
14+
But before we get into the details of how you define a decorator or an add-on, let's take a look at how schema form builds forms.
15+
16+
How the form is built
17+
----------------------
18+
Schema Form uses the [sfBuilder](https://github.com/Textalk/angular-schema-form/blob/development/src/services/builder.js)
19+
service to recursively build the DOM elements of the form from a *canonical form definition*, that
20+
is our fancy word for an internal representation of a merge between the schema and the form.
21+
22+
It's always an array of object and each object at least have the property `type`. If a `type` was
23+
not set in the form definition given to `sf-form` the schema is used to get a default.
24+
25+
Example canonical form def.
26+
```js
27+
[
28+
{
29+
type: 'text'
30+
key: 'name'
31+
},
32+
{
33+
type: 'fieldset',
34+
item: [
35+
{
36+
type: 'textarea',
37+
key: 'comment'
38+
}
39+
]
40+
}
41+
]
42+
```
43+
44+
#### The actual building
45+
So to build a form from a canonical form definition as in the example above the builder service loops
46+
over and for each type asks the decorator for a template, it adds it to a document fragment.
47+
48+
After adding the template it also asks the decorator if that type has a *builder*
49+
function (actually it's usually a list of functions). If so it calls it with the DOM of its template,
50+
the form definition for that field and other useful stuff. This way the builder can modify and
51+
prepare the template depending on options in that fields form object.
52+
53+
Nested fields, as with the fieldset above in the example above, builds it's children with such a
54+
*builder* function.
55+
56+
This all happens in one large swoop and the finished document fragment is popped inside the form
57+
and then `$compile` is used to kick start it's directives.
58+
59+
60+
Creating an add-on
61+
------------------
62+
63+
So to create an add-on you need two things, a template and some *builder functions*. Fortunately
64+
schema form got you covered with a couple of standard builders so most of the time you will only
65+
need a template.
66+
67+
To register your template to be used when the form definition has a specific type you use the
68+
`schemaFormDecoratorsProvider.defineAddOn`.
69+
70+
Ex.
71+
```js
72+
angular.module('myAddOnModule', ['schemaForm']).config(function(schemaFormDecoratorsProvider, sfBuilderProvider) {
73+
74+
schemaFormProvider.defineAddOn(
75+
'bootstrapDecorator', // Name of the decorator you want to add to.
76+
'awesome', // Form type that should render this add-on
77+
'templates/my/addon.html', // Template name in $templateCache
78+
sfBuilderProvider.stdBuilders // List of builder functions to apply.
79+
);
80+
81+
});
82+
```
83+
84+
The standards builders are `[sfField, ngModel, ngModelOptions, condition]`, see usage details below.
85+
86+
#### The Template
87+
So whats in a template? You usually need a couple of things:
88+
89+
1. Usually a top level element that surrounds your template is a good idea. The `sfField` builder
90+
slaps on a `sfField` directive that exposes the current form object on scope as `form`.
91+
1. A `sf-field-model` somewhere so that the `ngModel` builder can add a proper `ngModel` to bind
92+
your model value to.
93+
1. A `schema-validate="form"` directive on the same element to enable schema validation.
94+
1. A `<div sf-message="form.description"></div>` to display description or error messages.
95+
96+
Basic template example:
97+
```html
98+
<div> <!-- Surrounding DIV for sfField builder to add a sfField directive to. -->
99+
<label>{{form.title}}</div>
100+
<input sf-field-model schema-validate="form" type="text">
101+
<div sf-message="form.description"></div>
102+
</div>
103+
```
104+
105+
**BIG FAT CAVEAT**
106+
Ok, so currently there is something really ugly here. The bootstrap (and material) decorator uses
107+
a build step (gulp-angular-templatecache) to "compile" the template into a javascript file that
108+
basically chucks the template into `$templateCache`. Currently schema form does *not* support
109+
loading the templates any other way. They need to be in `$templateCache` when rendering.
110+
111+
This is really ugly and will be fixed. But you have been warned!
112+
113+
114+
Defining a decorator
115+
--------------------
116+
Defining a decorator is basically the same as defining a lot of add-ons. As with add-ons you use
117+
the `schemaFormDecoratorsProvider` again. This time its
118+
`schemaFormDecoratorsProvider.defineDecorator`.
119+
120+
Ex.
121+
```js
122+
angular.module('myDecoratorModule', ['schemaForm']).config(function(schemaFormDecoratorsProvider, sfBuilderProvider) {
123+
124+
schemaFormDecoratorsProvider.defineDecorator('awesomeDecorator', {
125+
textarea: {template: base + 'textarea.html', builder: sfBuilderProvider.stdBuilders},
126+
button: {template: base + 'submit.html', builder: sfBuilderProvider.stdBuilders},
127+
text: {template: base + 'text.html', builder: sfBuilderProvider.stdBuilders},
128+
129+
// The default is special, if the builder can't find a match it uses the default template.
130+
'default': {template: base + 'default.html', builder: sfBuilderProvider.stdBuilders}
131+
}, []);
132+
});
133+
```
134+
135+
### Setting up schema defaults
136+
So you got this shiny new add-on or decorator that adds a fancy field type, but feel a bit bummed out that you
137+
need to specify it in the form definition all the time? Fear not because you can also add a "rule"
138+
to map certain types and conditions in the schema to default to your type.
139+
140+
You do this by adding to the `schemaFormProvider.defaults` object. The `schemaFormProvider.defaults`
141+
is an object with a key for each type *in JSON Schema* with a array of functions as its value.
142+
143+
```javscript
144+
var defaults = {
145+
string: [],
146+
object: [],
147+
number: [],
148+
integer: [],
149+
boolean: [],
150+
array: []
151+
};
152+
```
153+
154+
When schema form traverses the JSON Schema to create default form definitions it first checks the
155+
*JSON Schema type* and then calls on each function in the corresponding list *in order* until a
156+
function actually returns something. That is then used as a defualt.
157+
158+
This is the function that makes it a datepicker if its a string and has format "date" or "date-time":
159+
160+
```javascript
161+
var datepicker = function(name, schema, options) {
162+
if (schema.type === 'string' && (schema.format === 'date' || schema.format === 'date-time')) {
163+
var f = schemaFormProvider.stdFormObj(name, schema, options);
164+
f.key = options.path;
165+
f.type = 'datepicker';
166+
options.lookup[sfPathProvider.stringify(options.path)] = f;
167+
return f;
168+
}
169+
};
170+
171+
// Put it first in the list of functions
172+
schemaFormProvider.defaults.string.unshift(datepicker);
173+
```
174+
175+
### Sharing your add-on with the world
176+
So you made an add-on, why not share it with us? On the front page,
177+
[http://textalk.github.io/angular-schema-form/](http://textalk.github.io/angular-schema-form/#third-party-addons), we
178+
maintain a list of add ons based on a query of the bower register, and we love to see your add-on
179+
there.
180+
181+
Any [bower](http://bower.io) package with a name starting with `angular-schema-form-` or that has
182+
the `keyword` `angular-schema-form-add-on` in its `bower.json` will be picked up. It's cached so
183+
there can be a delay of a day or so.
184+
185+
So [make a bower package](http://bower.io/docs/creating-packages/), add the keyword
186+
`angular-schema-form-add-on` and [register it](http://bower.io/docs/creating-packages/#register)!
187+
188+
189+
190+
191+
The builders
192+
------------
193+
TODO: API docs for each builder
194+
195+
196+
Useful directives
197+
-----------------
198+
TODO: more in depth about schema-validate and sf-messages

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ IMPORTANT
55
**Angular Schema Form is undergoing a refactoring and the "bootstrap decorator", i.e. the part with
66
all the HTML has been moved to [github.com/Textalk/angular-schema-form-bootstrap](https://github.com/Textalk/angular-schema-form-bootstrap).**
77

8-
The documentation below, especially form options is therefore somwhat bootstrap decorator
8+
The documentation below, especially form options is therefore somewhat bootstrap decorator
99
specific. The docs is undergoing updating.
1010

1111

0 commit comments

Comments
 (0)