npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mongoose-formulate

v2.0.0

Published

Mongoose plugins to faciliate dynamic form based input based on custom templates

Downloads

3

Readme

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: '[email protected]'
						}
					]
				}
			]
		}, {
			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 [email protected]'
						}
					]
				},
				{
					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 [email protected]'
						}
					]
				},
				{
					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 [email protected]'
						}
					]
				}
			]
		}]
	}
})

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