mongoose-formulate

2.0.0 • Public • Published

Mongoose Formulate

Mongoose Formulate is a package of 2 mongoose plugins that allow you to bake a programmable CMS into your existing applications. It's intended to be used to build a framework that allows dynamic creation of form templates that in turn structure input that is stored in entries.

What is it for?

If you need a system for allowing users of your application to define custom form templates based on common input formats and a flexible way to store data submitted against those templates, Formulate is for you. Think of it as a pluggable CMS. If your looking for a full-blown CMS solution then it's not for you. There is no UI component, everything is powered programmtically and the UIs for the fieldtypes, templates and forms must be implemented by you. This is by design.

How to use it

npm install mongooose-formulate

First you need to setup the template plugin:

// install the template plugin on an existing collection, or create a generic 'templates collection'
var mongoose = require('mongoose');
var formulate = require('mongoose-formulate')
var Schema = mongoose.Schema;

// the plugin only adds additional fields to your schema, so you can add
// specific custom schema fields as you wish. Name would be an obvious one
var schema = {
    name: String
};

schema.plugin(formulate.templatePlugin);
var TemplateModel = mongoose.model('template', schema);

Next setup the entry plugin. This is where your form content will be stored. Because this is just a mongoose plugin you add it to any of your exisiting collections (giving your form content 'context') or create a generic entries collection for ultimate flexiblity.

var mongoose = require('mongoose');
var formulate = require('mongoose-formulate')
var Schema = mongoose.Schema;

var myExistingSchema = {
    name: String,
    created: Date
};

schema.plugin(formulate.entryPlugin);
var MyModel = mongoose.model('my-model', schema);

Once the two plugins are setup, you can start adding custom templates. Here is an example of a Resume template:

There is an explanation of the formGroups, fieldGroups and fields properties below.

TemplateModel.new({
  name: Resume Template',
    template: {
        formGroups: [{
            label: 'Personal Information',
            description: 'Enter you personal information for your Resume',
            // repeatable: 1, will default to 1 when not specified
            fieldGroups: [
                {
                    fields: [
                        {
                            label: 'First Name',
                            fieldtype: 'text'
                        },
                        {
                            label: 'Last Name',
                            fieldtype: 'text'
                        },
                        {
                            label: 'Date of Birth',
                            fieldtype: 'datetime'
                        },
                        {
                            label: 'Email',
                            fieldtype: text
                        }
                    ]
                }
            ]
        }, {
            label: 'Employment History',
            description: 'Specify your 3 previous employers',
            repeatable: 3,
            fieldGroups: [
                {
                    fields: [
                        {
                            label: 'Company',
                            fieldtype: 'text',
                            validation: {
                                required: true
                            }
                        },
                        {
                            label: 'Start Date',
                            fieldtype: datetime,
                            validation: {
                                required: true
                            }
                        },
                        {
                            label: 'End Date',
                            description: 'Leave blank if not applicable',
                            fieldtype: 'datetime'
                        },
                        {
                            label: 'Company Contact Name / Number',
                            fieldtype: 'text'
                        }
                    ]
                }
            ]
        }]
    }
})

You could then use this resuable template to generate 'entries' via your client applications, e.g. Mobile App or Web App. Your client will need to interpret these templates (this is the part you have to write yourself) so they can display some kind of form to the end user.

The entry mimicks the schema of the template, with the addition of a value property on the fields. An entry document might be created like so:

MyModel.new({
    name: 'Custom entry name',
    content: {
        formGroups: [{
            label: 'Personal Information',
            description: 'Enter you personal information for your Resume',
            repeatable: 1,
            fieldGroups: [
                {
                    fields: [
                        {
                            label: 'First Name',
                            fieldtype: 'text',
                            value: 'Joe'
                        },
                        {
                            label: 'Last Name',
                            fieldtype: 'text',
                            value: 'Bloggs'
                        },
                        {
                            label: 'Date of Birth',
                            fieldtype: 'datetime',
                            value: 'Fri Apr 24 1987 13:44:48 GMT+1000 (AEST)'
                        },
                        {
                            label: 'Email',
                            fieldtype: text,
                            value: 'info@example.com'
                        }
                    ]
                }
            ]
        }, {
            label: 'Employment History',
            description: 'Specify your 3 previous employers',
            repeatable: 3,
            fieldGroups: [
                {
                    fields: [
                        {
                            label: 'Company',
                            fieldtype: 'text',
                            validation: {
                                required: true
                            },
                            value: 'IBM'
                        },
                        {
                            label: 'Start Date',
                            fieldtype: datetime,
                            validation: {
                                required: true
                            },
                            value: 'Mon Jan 01 2000 00:00:00 GMT+1000 (AEST)'
                        },
                        {
                            label: 'End Date',
                            description: 'Leave blank if not applicable',
                            fieldtype: 'datetime',
                            value: 'Mon Jan 01 2005 00:00:00 GMT+1000 (AEST)'
                        },
                        {
                            label: 'Company Contact Name / Number',
                            fieldtype: 'text',
                            value: 'Mary Jones mary@example.com'
                        }
                    ]
                },
                {
                    fields: [
                        {
                            label: 'Company',
                            fieldtype: 'text',
                            validation: {
                                required: true
                            },
                            value: 'Microsoft'
                        },
                        {
                            label: 'Start Date',
                            fieldtype: datetime,
                            validation: {
                                required: true
                            },
                            value: 'Mon Jan 01 2005 00:00:00 GMT+1000 (AEST)'
                        },
                        {
                            label: 'End Date',
                            description: 'Leave blank if not applicable',
                            fieldtype: 'datetime',
                            value: 'Mon Jan 01 2010 00:00:00 GMT+1000 (AEST)'
                        },
                        {
                            label: 'Company Contact Name / Number',
                            fieldtype: 'text',
                            value: 'Mary Jones mary@example.com'
                        }
                    ]
                },
                {
                    fields: [
                        {
                            label: 'Company',
                            fieldtype: 'text',
                            validation: {
                                required: true
                            },
                            value: Google
                        },
                        {
                            label: 'Start Date',
                            fieldtype: datetime,
                            validation: {
                                required: true
                            },
                            value: 'Mon Jan 01 2010 00:00:00 GMT+1000 (AEST)'
                        },
                        {
                            label: 'End Date',
                            description: 'Leave blank if not applicable',
                            fieldtype: 'datetime'
                        },
                        {
                            label: 'Company Contact Name / Number',
                            fieldtype: 'text',
                            value: 'Mary Jones mary@example.com'
                        }
                    ]
                }
            ]
        }]
    }
})

As you can see it is a very flexible way to store data based on freeform data (e.g. data you will cannot define a schema for in advance).

Overview

There are 3 components to Formulate: Fieldtypes, Templates and Entries.

Fieldtypes

Fieldtypes are the building blocks of your templates. They are a basic from of common inputs that should be flexible enough to handle most 'form content'.

Currently Formulate has the following fieldtypes:

  • Text
  • Number
  • Datetime
  • Select
  • Relationship
  • Switch
  • List

Each of the fields has validation (required, min, max) options which allows customisation of input you store in your entries.

Templates

Templates can be thought of as a Form Builder. Imagine templates as a way to programmatically store your content structures as you would in your CMS – Heads up: Formulate handles only the logic of structuring and storing your content. There is no UI component to this package, that part is up to you!

Entries

Entries are where the data for a submitted template is stored. Entries mimick the schema used for the template they were based on, but there is no definite relationship between the two. E.g. Once an entry is created, it holds a copy of the template it was based on, so existing templates can be safely updated without affecting historical entries.

Template Form Groups, Field Groups and Fields

As you can see form the example above, the schema for templates features the following properties which make up a form template:

  • Form Groups
  • Field Groups
  • Fields

Each is a child of the previous and helps to build a flexible form structure to handle most types of input data. The following illustrates the structure of a form:

Formulate Illustration

Form Groups

The top level array that holds 'sections' of your forms. Imagine form group items as being independant sections of your form. E.g. if you were creating resume input, your formGroups might be 'Personal Information', 'Work History' and 'Education'.

Field Groups

Field Groups are an array as well, which is important as it allows us to accept repeatable input based on a single template.

Take the resume example again, the work history section would be based on a template (Company, Start, End, Contact) that can be repeated. That is a fieldGroup. If you don't want the group of fields to be repeated, e.g. for Personal Information you wouldn't want to repeat the input, then you just set the repeatable property of the formGroup to 1.

For unlimited inputs, set repeatable to 0 and for anything else set the number you want to limit by, e.g. 4.

Fields

Fields make up your fieldGroups and represent an individual input for the form. For the resume example, the Personal Information form group would be made up of one fieldGroup with the fields First Name, Last Name, DoB, Address, Email etc.

Fields have a fieldtype property which is explained here

Useful things to remember about Formulate

  • It's your job to build UIs for your forms/templates. Formulate only handles the programatical side of building templates and validating and storing your entries
  • The schema for templates are identical to entries so that both can be edited independantly in the future
  • formGroups are like 'sections' of your forms
  • fieldGroups hold related fields and can be repeatable to support multiple items
  • fields are individual inputs on your forms and are grouped in fieldGroups
  • Values are important to entries, but not so much for templates. Although you can use the value property on a template to act as a custom default value

Readme

Keywords

none

Package Sidebar

Install

npm i mongoose-formulate

Weekly Downloads

2

Version

2.0.0

License

MIT

Last publish

Collaborators

  • willmcclellan