├── .gitignore ├── .npmignore ├── package.json ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .swp 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .swp 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Greg Miell ", 3 | "name": "forms-mongoose", 4 | "homepage": "https://github.com/GothAck/forms-mongoose", 5 | "description": "Generate forms from Mongoose Models", 6 | "version": "0.0.6", 7 | "main": "./index", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://GothAck@github.com/GothAck/forms-mongoose.git" 11 | }, 12 | "keywords": [ 13 | "mongoose", 14 | "forms", 15 | "mongo" 16 | ], 17 | "dependencies": { 18 | "forms": "*", 19 | "underscore": ">= 1.3.1" 20 | }, 21 | "devDependencies": {}, 22 | "optionalDependencies": {} 23 | } 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Forms-mongoose allows auto-generation of forms from your Mongoose models 2 | 3 | http://search.npmjs.org/#/forms-mongoose 4 | 5 | ### Example 6 | 7 | #### Mongoose 8 | 9 | ```javascript 10 | var mongoose = require('mongoose'); 11 | var Schema = mongoose.Schema; 12 | var Email = mongoose.SchemaTypes.Email; 13 | var forms = require('forms-mongoose'); 14 | 15 | var AddressSchema = new Schema({ 16 | category: {type: String, required: true, default: 'home', forms: {all:{}}}, 17 | lines: {type: String, required: true, forms:{all:{widget:forms.widgets.textarea({rows:3})}}}, 18 | city: {type: String, required: true} 19 | }); 20 | 21 | var PersonSchema = new Schema({ 22 | email: { type: Email, unique: true, forms: { 23 | all: { 24 | type: 'email' 25 | } 26 | }}, 27 | confirmed: { type: Boolean, required: true, default: false }, 28 | name: { 29 | first: { type: String, required: true, forms: { 30 | new: {}, 31 | edit: {} 32 | }}, 33 | last: { type: String, required: true, forms: { 34 | new: {}, 35 | edit: {} 36 | }} 37 | }, 38 | address: [AddressSchema] 39 | }); 40 | 41 | var PersonModel = mongoose.model('Person', PersonSchema); 42 | ``` 43 | 44 | #### Convert Mongoose Model to Forms Object 45 | 46 | ```javascript 47 | var forms = require('forms-mongoose'); 48 | 49 | var form = forms.create(PersonModel, 'new'); // Creates a new form for a "new" Person 50 | 51 | // Use the form object as you would with Forms 52 | 53 | console.log (form.toHTML()); 54 | // Note toHTML does not include the
tags, this is to allow flexibility. 55 | 56 | //optionally create some static methods in the schema 57 | 58 | PersonSchema.statics.createForm = function (extra) { 59 | return forms.create(this, extra); 60 | } 61 | 62 | PersonSchema.statics.createAddressForm = function (extra) { 63 | return forms.create(this.schema.paths.address, extra); 64 | } 65 | ``` 66 | 67 | ### Requirements 68 | 69 | - [Node.js](http://nodejs.org/) 70 | 71 | ### Installation 72 | 73 | ``` 74 | npm install forms-mongoose 75 | ``` 76 | 77 | 78 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var forms = require('forms') 2 | , fields = forms.fields 3 | , widgets = forms.widgets 4 | , validators = forms.validators 5 | , _ = require('underscore'); 6 | 7 | var _fields = { 8 | 'String': 'string', 9 | 'Number': 'number', 10 | 'Password': 'password', 11 | 'Email': 'email', 12 | 'Date': 'string', 13 | 'Boolean': 'boolean' 14 | } 15 | 16 | function convert_mongoose_field(mongoose_field) { 17 | return fields[_fields[mongoose_field] || fields.string]; 18 | } 19 | 20 | function get_field(path, form_name, form_category) { 21 | var _field = null; 22 | if (!(path.options && path.options.forms)) 23 | return null; 24 | var forms = path.options.forms; 25 | if (! ( 26 | forms[form_name] || 27 | (forms['all'] && !forms[form_category]) || 28 | (forms[form_category] && forms[form_category].all) || 29 | (forms[form_category] && forms[form_category][form_name]) || 30 | (form_name === '*' && forms._all) 31 | )) 32 | return null; 33 | 34 | var _options = _.extend( 35 | {} 36 | , forms._all 37 | , forms.all 38 | , forms[form_name] 39 | , form_category && forms[form_category] && forms[form_category]._all 40 | , form_category && forms[form_category] && forms[form_category].all 41 | , form_category && forms[form_category] && forms[form_category][form_name] 42 | ); 43 | 44 | if (_options.type) 45 | _field = (typeof _options.type === 'string') ? fields[_options.type] : _options.type 46 | if (!_field) 47 | _field = convert_mongoose_field( path.options.type ? path.options.type.name : path.instance ); 48 | if (!_field) 49 | throw new Error('Model does not have forms.type, probably on a virtual', path); 50 | 51 | 52 | var _fields = {} 53 | _options = _.defaults(_options, { 54 | required: ( (typeof _options.required === 'undefined') ? (path.options.required || path.options.unique) : _options.required), 55 | validators: [] 56 | }); 57 | if (path.validators) 58 | for (var i = path.options.required ? 1 : 0; i < path.validators.length; i ++) 59 | (function (validator) { 60 | _options.validators.push(function (form, field, callback) { 61 | callback(validator[0](field.value) ? undefined : validator[1]); 62 | }); 63 | })(path.validators[i]); 64 | _fields[path.path] = null; 65 | if (_options.confirm) { 66 | var _options_confirm = _.clone(_options); 67 | _options_confirm.validators = _options.validators.slice(0) 68 | _options_confirm.validators.unshift(validators.matchField(path.path)); 69 | _fields[path.path + '.confirm'] = _field(_options_confirm); 70 | } 71 | if(_options.existing) { 72 | var _options_existing = _.clone(_options); 73 | _options_existing.validators = [function (form, field, callback) { 74 | if (!form.existing) 75 | return callback('Server error'); 76 | var existing = form.existing[path.path]; 77 | if (typeof existing === 'function') { 78 | existing(field.data, function (err, result) { 79 | if (err) return callback('Server error: ' + err); 80 | if (!result) return callback('Does not match existing value!!!'); 81 | callback(); 82 | }); 83 | } else if (form.existing[field.name] != field.data) { 84 | return callback('Does not match existing value!'); 85 | } else { 86 | callback(); 87 | } 88 | }]; 89 | _fields[path.path + '.existing'] = _field(_options_existing); 90 | } 91 | _options.validators.unshift(function (form, field, callback) { 92 | if (field.data && _options.confirm) 93 | form.fields[path.path + '.confirm'].required = true; 94 | if (field.data && _options.existing) 95 | form.fields[path.path + '.existing'].required = true; 96 | callback(); 97 | }); 98 | _fields[path.path] = _field(_options); 99 | return _fields; 100 | } 101 | 102 | module.exports.create = function (model, extra_params, form_name, form_category) { 103 | var schema = model.schema 104 | , paths = schema.paths 105 | , virtuals = schema.virtuals 106 | , params = {}; 107 | for (var pathName in paths) { 108 | var path = paths[pathName]; 109 | var field = get_field(path, form_name, form_category); 110 | if (field) 111 | params = _.extend(params, field); 112 | } 113 | for (var virtName in virtuals) { 114 | var virt = virtuals[virtName]; 115 | virt.path = virtName; 116 | var field = get_field(virt, form_name, form_category); 117 | if (field) 118 | params = _.extend(params, field); 119 | } 120 | params = _.extend({}, params, extra_params); 121 | var form = forms.create(params); 122 | return form; 123 | } 124 | 125 | module.exports.fields = fields; 126 | module.exports.widgets = widgets; 127 | module.exports.validators = validators; 128 | module.exports.createForm = function (params, extra_params) { 129 | params = _.extend({}, params, extra_params); 130 | var form = forms.create(params) 131 | return form; 132 | } 133 | --------------------------------------------------------------------------------