AutoForm
AutoForm is a Meteor package that adds UI components and helpers to easily create basic forms with automatic insert and update events, and automatic reactive validation. Versions 6+ of this package require that you separately install the simpl-schema NPM package. Prior versions require and automatically install the simple-schema Meteor package. You can optionally use it with the collection2 package, which you have to add to your app yourself.
NOTE: AutoForm 7.0
AutoForm 7.0 is now available and decouples from the default themes. You will have to install themes manually!
Be sure to check out the change log for full details, first. Note that if you use add-on packages that haven't been updated yet, you will not yet be able to update to version 6.
Add-on Package Authors: Please test your package against AutoForm 7.0, and then release a major version update in which you change your api.use to api.use('aldeed:autoform@7.0.0');.
We do NOT recommend using something like api.use('aldeed:autoform@6.0.0 || 7.0.0'); to try to support multiple major versions of AutoForm because there is currently a known Meteor issue where trying to support too many dependency paths leads to running out of memory when trying to resolve dependencies.
Table of Contents
Table of Contents generated with DocToc
- Installation
- Demo
- Example
- Component and Helper Reference
- Objects and Arrays
- Form Types
- Public API
- Non-Collection Forms
- Fine Tuning Validation
- Manual Validation
- Resetting Validation
- The Form Document
- Callbacks/Hooks
- Putting Field Attribute Defaults in the Schema
- Complex Schemas
- Dates
- Theme Templates
- Grouping Fields
- Sticky Validation Errors
- Defining Custom Input Types
- Common Questions
- Should the value of
schemaandcollectionhave quotation marks around it? - Which components should I use?
- Can I reuse the same
quickFormorautoFormfor both inserts and updates? - How can I show an asterisk after the label for required fields?
- What are the various ways I can specify options for a select, radio group, or checkbox group?
- Can I put HTML in my error messages?
- Should the value of
- Examples
- Troubleshooting
- Contributing
- Testing
- Credits
- License
Installation
In a Meteor app directory, enter:
$ meteor add aldeed:autoform
Also install SimpleSchema NPM package separately (AutoForm 6+):
$ npm i --save simpl-schema
And then also extend SimpleSchema to allow the autoform option in your schemas, if you plan to use it:
import SimpleSchema from 'simpl-schema'; SimpleSchema.extendOptions(['autoform']);
By default there is no theme included, so you will have to install a theme, too. The following themes are available and tested to work with v7:
Please also consider, that twbs:bootstrap is depending on an outdated (and potential insecure!) Bootstrap version.
Better: Use the latest Bootstrap 3.x or 4.x from NPM in favour.
Migration from 6.x
If you update to 7.0.0 you will likely encounter errors from your extension packages like
While selecting package versions: error: Conflict: Constraint aldeed:autoform@6.3.0 is not satisfied by aldeed:autoform 7.0.0. Constraints on package "aldeed:autoform": * aldeed:autoform@=7.0.0 <- top level * aldeed:autoform@6.3.0 <- someone:packagename x.y.z
You can easily circumvent this issue by editing the package entry in .meteor/packages
from aldeed:autoform to aldeed:autoform@7.0.0! (note the exclamation mark).
This is because many extensions will not have the 7.0.0 reference in their
package.js file, yet. However, this major version is intended to not break
compatibility with extensions, that worked with 6.x. If you encounter any
runtime issues with extensions, please open an issue.
Import using static imports
If you come from a previous version and want to "keep things as they were" then this is the option you should choose.
AutoForm now comes only with the core functionality added to the initial package
code. In order to make the Templates available, too, you only need to
put the following line into your top-level client startup code (for example
imports/startup/client/autoform.js):
1import 'meteor/aldeed:autoform/static'
That's it. The Templates are now available.
Import using dynamic imports
This package supports dynamic-import, which helps to reduce initial bundle
size of the package from ~110 KB to ~60 KB (estimated via bundle-visualizer).
The following example shows how to import the packages dynamically:
1import 'meteor/aldeed:autoform/dynamic' 2 3AutoForm.load() 4 .then(() => { 5 // ... on init success code, for example set a ReactiveVar to true 6 )) 7 .catch(e => { 8 // ... on error code 9 })
You can even combine this with one of the themes (if they support dynamic imports) like in the following example:
1import { AutoFormThemeBootstrap4 } from 'meteor/communitypackages:autoform-bootstrap4/dynamic' 2import 'meteor/aldeed:autoform/dynamic' 3 4async function init () { 5 await AutoForm.load() 6 await AutoFormThemeBootstrap4.load() 7 // theme is imported, you can now make the form available 8 // you could use a reactive var that resolves to true here 9 // or any other mechanism you like to use to reactively activate the form 10 AutoForm.setDefaultTemplate('bootstrap4') 11} 12 13(function () { 14 init() 15 .catch(e => console.error('[autoForm]: init failed - ', e)) 16 .then(() => console.info('[autoForm]: initialized')) 17})()
Note, that you can't use the #autoForm or >quickForm Templates before the
import has not completed. You can however use a ReactiveVar in your Temlate
to "wait" with rendering the form:
1import { ReactiveVar } from 'meteor/reactive-var' 2import { initAutoForm } from 'meteor/aldeed:autoform/dynamic' 3 4const autoFormLoaded = new ReactiveVar() 5 6initAutoForm() 7 .then(() => autoFormLoaded.set(true)) 8 .catch(e => { 9 // ... on error code 10 }) 11 12// ... other Template code 13 14Template.myCoolForm.helpers({ 15 loadComplete() { 16 return autoFormLoaded.get() 17 } 18})
Community Add-On Packages
Submit a pull request to add your package to this list!
Custom Input Types
Dates and times:
- aldeed:autoform-bs-datepicker
- aldeed:autoform-bs-datetimepicker
- miguelalarcos:afwrap-xdatetime
- notorii:autoform-datetimepicker
- lukemadera:autoform-pikaday
- antalakas:autoform-bs-daterangepicker
- drewy:autoform-datetimepicker
- bookmd:autoform-time-from-now
- jkutianski:autoform-datemask
Selects:
- aldeed:autoform-select2
- aldeed:autoform-bs-button-group-input
- comerc:autoform-selectize
- vazco:universe-autoform-select
- lukemadera:autoform-autocomplete
- rikonor:autoform-image-gallery
- newnectar:meteor-autoform-select-country-flags
WYSIWYGs:
Markdowns:
Autocompletes:
- comerc:autoform-placecomplete
- miguelalarcos:afwrap-xautocomplete
- comerc:autoform-typeahead
- lukemadera:autoform-googleplace
- lukemadera:autoform-autocomplete
Files:
- cfs:autoform
- yogiben:autoform-file
- naxio:autoform-file
- elevatedevdesign:autoform-slingshot
- ostrio:autoform-files
- universe:files-blaze-ui
Maps:
Ranges/Sliders:
Payments
Other:
Themes
- meteoric:autoform-ionic
- fabienb4:autoform-semantic-ui
- mozfet:autoform-materialize
- mozfet:autoform-modals-materialize
- poetic:react-autoform-material-ui
Admin Panels
Content Management Systems
Components
Other
Demo
Example
Let's say you have the following Mongo.Collection instance, with schema support
provided by the collection2 package. (Adding autoform to your app does not add
collection2 by default so you need to run meteor add aldeed:collection2@3.0.0 for this example
to work.)
1Books = new Mongo.Collection("books"); 2Books.attachSchema(new SimpleSchema({ 3 title: { 4 type: String, 5 label: "Title", 6 max: 200 7 }, 8 author: { 9 type: String, 10 label: "Author" 11 }, 12 copies: { 13 type: Number, 14 label: "Number of copies", 15 min: 0 16 }, 17 lastCheckedOut: { 18 type: Date, 19 label: "Last date this book was checked out", 20 optional: true 21 }, 22 summary: { 23 type: String, 24 label: "Brief summary", 25 optional: true, 26 max: 1000 27 } 28}, { tracker: Tracker }));
Be sure to define proper insert security for untrusted code if you've removed the insecure package. Call allow/deny or use ongoworks:security.
A Basic Insert Form
1<template name="insertBookForm"> 2 {{> quickForm collection="Books" id="insertBookForm" type="insert"}} 3</template>
That's it! This gives you:
- An autogenerated form that uses the appropriate classes, depending on your theme.
- Appropriate HTML5 fields for all keys in the "Books" collection schema.
- A submit button that gathers the entered values and inserts them into
the "Books" collection.
- Form validation based on the schema attached to the "Books" collection. By default the form
is validated when the user submits. If anything is invalid, the form is continually re-validated on keyup (throttled) as the user fixes the issues.
- Default validation error messages that appear under the fields, and can be
customized and translated.
A Basic Update Form
An update form is similar to an insert form, except you need to provide the document with the original values to be updated:
1<template name="updateBookForm"> 2 {{> quickForm collection="Books" doc=this id="updateBookForm" type="update"}} 3</template>
This example uses doc=this, assuming that you use something like iron:router's data function to set the template's data context to the book document. This is a common way to do it, but you could also use a helper function that returns the document.
Be sure to define proper update security for untrusted code if you've removed the insecure package. Call allow/deny or use ongoworks:security.
A Custom Insert Form
If you want to customize autogenerated forms for all forms, you can easily
do so by writing your own templates. Refer to the templates section. However,
sometimes a certain form has a complex schema or unique UI requirements, in
which case you can use autoForm rather than quickForm, allowing you to
define fields individually.
Here's an example:
1<template name="insertBookForm"> 2 {{#autoForm collection="Books" id="insertBookForm" type="insert"}} 3 <fieldset> 4 <legend>Add a Book</legend> 5 {{> afQuickField name='title'}} 6 {{> afQuickField name='author'}} 7 {{> afQuickField name='summary' rows=6}} 8 {{> afQuickField name='copies'}} 9 {{> afQuickField name='lastCheckedOut'}} 10 </fieldset> 11 <button type="submit" class="btn btn-primary">Insert</button> 12 {{/autoForm}} 13</template>
In this example, we added rows=6 to the "summary" field, which will cause it
to be rendered as a textarea instead of a normal text input field.
Another Custom Insert Form
In the previous example of a custom insert form, we saw how afQuickField can
be used to render a field with simple customizations. Now let's say we need to
fully customize one of the fields. To do this, you can use the following more
specific templates and helpers:
- afFieldIsInvalid
- afFieldInput
- afFieldMessage
Here's an example:
1<template name="insertBookForm"> 2 {{#autoForm collection="Books" id="insertBookForm" type="insert"}} 3 <fieldset> 4 <legend>Add a Book</legend> 5 {{> afQuickField name='title'}} 6 {{> afQuickField name='author'}} 7 {{> afQuickField name='summary' rows=6}} 8 {{> afQuickField name='copies'}} 9 {{> afQuickField name='lastCheckedOut'}} 10 <div class="form-group{{#if afFieldIsInvalid name='cost'}} has-error{{/if}}"> 11 <div class="input-group"> 12 <span class="input-group-addon">$</span> 13 {{> afFieldInput name='cost'}} 14 <span class="input-group-addon">/each</span> 15 </div> 16 {{#if afFieldIsInvalid name='cost'}} 17 <span class="help-block">{{afFieldMessage name='cost'}}</span> 18 {{/if}} 19 </div> 20 </fieldset> 21 <button type="submit" class="btn btn-primary">Insert</button> 22 {{/autoForm}} 23</template>
We added a cost field to our form and customized it to display as an input
group with add-ons.
Component and Helper Reference
NOTE: The afDeleteButton component that used to be part of autoform is now available as a separate package.
autoForm
Use this component as a block instead of <form> elements to wrap your form and
gain all the advantages of the autoform package.
The following attributes are recognized:
collection: Required ifschemais not set. Set to one of the following:- The name of a helper function (no quotation marks) that returns an
instance of Mongo.Collection that has a schema defined.
* The name (in quotation marks) of a Mongo.Collection instance that has
a schema defined and is in the window namespace.
schema: Required ifcollectionis not set. This schema will be used to generate
and validate the form prior to submission, so you can specify this along with a
collection if you want to use a schema that is slightly different from
the one your collection uses. However, the final object will still have to pass
validation against the collection schema. Set to one of the following:
* The name of a helper function (no quotation marks) that returns an
instance of SimpleSchema.
* The name (in quotation marks) of a SimpleSchema instance that is in
the window namespace.
id: Required. This is used as theidattribute on the renderedform
element, so it must be unique within your entire application. It's required because we use it to set up a form-specific validation context and to preserve input values when a "hot code push" happens.
doc: Required for an update form, and must have at least an_idproperty. Pass the current document
object, retrieved with a call to findOne() for example. For an insert form,
you can also use this attribute to pass an object that has default form values
set (the same effect as setting a value attribute on each field within the form).
validation: Optional. See the "Fine Tuning Validation" section.template: Optional. See the "Templates" section.type: Optional. The form type. Default if not provided is "normal". See Form Types.meteormethod: Optional. Whentypeis "method" or "method-update", indicate the name of the
Meteor method in this attribute.
ddp: Optional. Whentypeis "method" or "method-update", provide an alternative DDP Connection that should be used to call the Meteor method in this attribute.resetOnSuccess: Optional. The form is automatically reset
for you after a successful submission action. You can skip this by setting this
attribute to false.
autosave: Optional. Set totrueto enable automatic form submission. Whenever theform changeevent is emitted, the change will be automatically saved to the database.autosaveOnKeyup: Optional. Set totrueto enable automatic form submission for atype="updateform onkeyupevent. Whenever akeyupevent is emitted on a form field, the change will be automatically saved to the database (throttled to 500ms). It's best to settrimStrings=falsewhen using this option. If you don't, spaces may be deleted while typing.filter: Optional. Set tofalsefor an insert or update form to skip filtering out unknown properties when cleaning the form document.autoConvert: Optional. Set tofalsefor an insert or update form to skip autoconverting property values when cleaning the form document.removeEmptyStrings: Optional. Set tofalsefor an insert or update form to keep empty string values when cleaning the form document.trimStrings: Optional. Set tofalsefor an insert or update form to keep leading and trailing spaces for string values when cleaning the form document.setArrayItems: Optional. Set totruefor an update form that is updating specific array items. Note that there is a quirk of MongoDB that will create objects instead of arrays when this is set totrue, if there is not already an array in the database. So if you set this totrue, be sure that the corresponding array property is nevernullor missing in the database. It must always be an array with 0 or more items.preserveForm: Optional. Set tofalseto disable preserving of form values across hot refreshes. This can sometimes help resolve issues with sticky form values.- Any additional attributes are passed along to the
<form>element, meaning that you can add classes, etc. When providing a boolean attribute, set it totrue(no quotation marks) or a helper that returnstrue.
quickForm
Use this component to generate an entire form in one line. It takes and requires
all the same attributes as autoForm. In addition, it recognizes the following
attributes:
type: Two additional type values are supported: "readonly" and "disabled".buttonClasses: Set the class attribute for the rendered submit button. Some templates may provide a default class if you don't set this.buttonContent: The submit button content. If you don't set this, "Submit" is used. If you set this tofalse, no submit button is rendered.fields: Optional. Bind an array or specify a comma-delimited string of field
names to include. Only the listed fields (and their subfields, if any) will be included, and they'll appear in the order you specify.
omitFields: Optional. Bind an array or specify a comma-delimited string of field
names to omit from the generated form. All first-level schema fields except the fields listed here (and their subfields, if any) will be included.
Any other attributes you specify will be output as attributes of the <form> element, just like when using the autoForm component. When providing a boolean attribute, set it to true (no quotation marks) or a helper that returns true.
See this demo for examples of what happens when you specify various types of fields in the fields or omitFields attributes.
afFieldInput
Renders an input control for the field. The type of control depends on what you set the type attribute to. All of the HTML5 input types plus a few more are built in. Here is the full list of included input types:
- boolean-checkbox
- boolean-radios
- boolean-select
- button
- color
- contenteditable
- date
- datetime
- datetime-local
- file
- hidden
- image
- month
- number
- password
- radio
- range
- reset
- search
- select
- select-checkbox
- select-checkbox-inline
- select-multiple
- select-radio
- select-radio-inline
- submit
- tel
- text
- textarea
- time
- url
- week
There are add-on packages that provide additional input types (widgets, UI controls).
If you don't include a type attribute, the following logic is used to automatically select an appropriate type:
- If you supply the
optionsattribute, aselectinput is used. If your schema expects an array for the field, then it is aselect-multipleinput. If you prefer radios or checkboxes (for example, if it is a short list of options), then addnoselect=trueattribute or simply set thetypetoselect-checkbox,select-checkbox-inline,select-radio, orselect-radio-inline. - Otherwise if the schema type is
Stringand you include therowsattribute, atextareais used. - Otherwise if the schema type is
Number, anumbertype is used. - Otherwise if the schema type is
Date, adatetype is used. - Otherwise if the schema type is
Boolean, theboolean-checkboxtype is used. You may want to specify atypeofboolean-radiosorboolean-selectinstead. If you do so, use thetrueLabel,falseLabel, andnullLabelattributes to set the labels used in the radio or select control. - Otherwise a
texttype is used.
The following attributes are recognized:
name: Required. The name of the schema key this field is for.template(default="bootstrap3"): Specify the name of a different built-in or
custom theme template to use.
options: An array of options objects (see below). By specifying options, you cause the generated DOM
element to be a select element with these options, unless you also use
noselect. To use the allowedValues from the schema as the options, set
options="allowed". To specify a label to be displayed when there is no
option selected, set firstOption="(My Select One Label)".
firstOption: Use with theoptionsattribute to specify a string to use for the first option of aselectinput, which shows when nothing has been selected yet. For example,firstOption="(You Should Really Pick Something From This List)". There is a default first option "(Select One)". If you don't want any default option, then dofirstOption=false, but make sure yourselectinput has a defaultvalueor this will result in a confusing UX where it looks like the first option is selected but it isn't.capitalize: Used only when you've setoptions="allowed". Set this totrue
to capitalize the labels generated from allowedValues.
noselect: Use in conjunction withoptionsattribute. Set this attribute
to true to render radios or checkboxes for the options instead of select.
trueLabel: Set to the string that should be used as the label for thetrue
option for an input with type boolean-select or boolean-radios.
falseLabel: Set to the string that should be used as the label for thefalse
option for an input with type boolean-select or boolean-radios.
nullLabel: Set to the string that should be used as the label for the empty value option for an input with typeboolean-selectorboolean-radios.value: Set a specific, potentially reactive, value for the input. If you have also provided adocattribute on theautoFormorquickForm, this value will override the value from thedocobject.defaultValue: Set a reactive default value for the input. If you have also provided adocattribute on theautoFormorquickForm, this value will be used only when thedocobject has no value for this field. This takes precedence over thedefaultValueproperty of the field's schema. (Also,defaultValuefrom the schema is slightly different in that it is never used if you provide adocattribute.)- Any additional attributes are passed along to the generated DOM element, meaning that you can add
class, etc. When providing a boolean attribute, set it totrue(no quotation marks) or a helper that returnstrue. placeholder: As with other attributes, this will be passed along to the
generated DOM element, but you can also optionally do
placeholder="schemaLabel" to use the field label defined in the schema as
the input's placeholder value.
- Each individual input type might accept and use additional attributes.
Here's an example of passing options to generate a select field:
html:
1{{> afFieldInput name="year" options=yearOptions}}
client.js:
1Template.registerHelper("yearOptions", function() { 2 return [ 3 {label: "2013", value: 2013}, 4 {label: "2014", value: 2014}, 5 {label: "2015", value: 201