amvm-form-models
Installation
npm install amvm-form-models --save
Running tests
npm test
Documentation
Example of form model
export class PersonFormModel {
constructor() {
'name.first': {
title: 'First name',
name: 'name.first',
value: 'John',
validators: [
{
validator: (value, formModel) => value.indexOf('error') === -1,
message: 'this is error for name.first',
type: 'error'
},
{
validator: (value, formModel) => value.indexOf('error') === -1,
message: 'this is error for name.first (duplicate)',
type: 'error'
},
{
validator: (value, formModel) => value.indexOf('warning') === -1,
message: 'this is warning for name.first',
type: 'warning'
},
{
validator: (value, formModel) => value.indexOf('info') === -1,
message: (value) => `this is info for name.first`,
type: 'info'
}
],
getJSON: function(value) { /* Optional function. Function should return value that will be saved into resulting json object */ }
},
'name.last': {
title: 'Last name',
name: 'name.last',
value: 'Brown',
validators: [
{
validator: (value, formModel) => value.indexOf('error') === -1,
message: 'this is error for name.last',
type: 'error'
},
{
validator: (value, formModel) => value.indexOf('error') === -1,
message: 'this is error for name.last (duplicate)',
type: 'error'
},
{
validator: (value, formModel) => value.indexOf('warning') === -1,
message: 'this is warning for name.last',
type: 'warning'
},
{
validator: (value, formModel) => value.indexOf('info') === -1,
message: (value) => `this is info for name.last`,
type: 'info'
}
]
},
'gender': {
value: 'male',
title: 'Gender',
name: 'gender',
dropdownValues: [
{ value: 'set-null', text: 'Select gender'},
{ value: 'male', text: 'Male'},
{ value: 'female', text: 'Female'}
]
},
'isAdult': {
title: 'Is adult',
name: 'isAdult',
value: true // value is boolean
},
'age': {
title: 'Age',
name: 'age',
value: 30, // value is number
validators: [
{
validator: (value, formModel) => value != 1,
message: 'this is error for age',
type: 'error'
},
{
validator: (value, formModel) => value != 2,
message: 'this is warning for age',
type: 'warning'
},
{
validator: (value, formModel) => value != 3,
message: (value) => `this is info for age`,
type: 'info'
}
]
},
phones: {
array: true, // set to true if object contains array of metas
def: {
name: 'phones[$key]', // $key will be replaced by real unique key
title: 'Phone',
validators: [
{
validator: (value, formModel) => value.indexOf('error') === -1,
message: 'this is error',
type: 'error'
},
{
validator: (value, formModel) => value.indexOf('warning') === -1,
message: 'this is warning',
type: 'warning'
},
{
validator: (value, formModel) => value.indexOf('info') === -1,
message: 'this is info',
type: 'info'
}
]
},
getJSON: function(meta) { /* Optional function. Function should return value that will be saved into resulting json object */ },
values: [
{
value: '555',
key: 'key1',
title: 'Phone',
name: 'phones[key1]'
},
{
value: '333',
key: 'key2',
title: 'Phone',
name: 'phones[key2]'
},
]
},
emails: {
array: true, // set to true if object contains array of metas
complex: true, // set to true if object contains array of objects, where each object contains several metas
def: {
type: {
name: 'emails[$key].type',
title: 'E-mail type',
validators: [
{
validator: (value, formModel) => value.indexOf('error') === -1,
message: 'this is error for emails[].type',
type: 'error'
},
{
validator: (value, formModel) => value.indexOf('warning') === -1,
message: 'this is warning for emails[].type',
type: 'warning'
},
{
validator: (value, formModel) => value.indexOf('info') === -1,
message: 'this is info for emails[].type',
type: 'info'
}
]
},
email: {
name: 'emails[$key].email', // $key will be replaced by real unique key
title: 'E-mail',
validators: [
{
validator: (value, formModel) => value.indexOf('error') === -1,
message: 'this is error for emails[].email',
type: 'error'
},
{
validator: (value, formModel) => value.indexOf('warning') === -1,
message: 'this is warning for emails[].email',
type: 'warning'
},
{
validator: (value, formModel) => value.indexOf('info') === -1,
message: 'this is info for emails[].email',
type: 'info'
}
]
}
},
getJSON: function(objectWithMetas) { /* Optional function. Function should return value that will be saved into resulting json object */ },
values: [
{
key: 'key1',
type: {
value: 'Work',
title: 'E-mail type',
name: 'emails[key1].type'
},
email: {
value: 'user@work.com',
title: 'E-mail',
name: 'emails[key1].email'
}
},
{
key: 'key2',
type: {
value: 'Personal',
title: 'E-mail type',
name: 'emails[key2].type'
},
email: {
value: 'user@personal.com',
title: 'E-mail',
name: 'emails[key2].email'
}
}
]
},
_model: {
validators: [
{
validator: (formModel) => formModel['name.first'].value.indexOf('meta_err') === -1,
message: 'this is _model validator',
type: 'error'
},
{
validator: (formModel) => formModel['name.first'].value.indexOf('meta_err') === -1,
message: 'this is _model validator',
type: 'error'
},
{
validator: (formModel) => formModel['name.first'].value.indexOf('meta_warn') === -1,
message: 'this is _model validator',
type: 'warning'
},
{
validator: (formModel) => formModel['name.first'].value.indexOf('meta_inf') === -1,
message: 'this is _model validator',
type: 'info'
}
],
errors: [],
warnings: [],
infos: []
}
}
}
In this class, name.first
property is meta object. Meta object has following properties:
Property | Description |
---|---|
value | This property will contain value for meta object |
title | Title of meta object. Usually value of title is used inside <label>
|
required | If set to true, <label> tag will display *
|
maxlength | This value will be set as maxlength attribute on <input> tag |
name | Value of name property is used for name atribute of input tag |
errors[] | Array of errors after running all validators against value property |
warnings[] | Array of warnings after running all validators against value property |
infos[] | Array of info messages after running all validators against value property |
dropdownValues | Array of object. Each object should have value and text property. This array can be used to build dropdown with these values. |
validators | Array if validators. validators property should be added to metas that are not part of array. |
getJSON | Optional function. If it exists, it will be used to create json for meta/array item. |
def | Object that describes array item. Array item might contain single meta object or object with multiple meta objects. For arrays, def should have validators array. |
phones
property is array. Each array item contains meta object with additional member called key
.
emails
property is array. Each array item contains obejct with key
property, and many meta objects. Thats why name
property of each meta obejct has format of emails[some_unique_key].%property_name%
_model
is special property that contains errors, warnings and infos arrays. These arrays will be created by complex validators in '_model' field. Complex validation does not belong to specific meta. Complex validation validates whole form model.
Resulting JSON will have following shape:
{
name : {
first: 'John'
last: 'Bown'
},
isAdult: true,
age: 30,
phones: [
{
key: 'key1',
value: '555'
},
{
key: 'key2',
value: '333'
}
],
emails: [
{
key: 'key1',
value: {
type: 'Work',
email: 'user@work.com'
}
},
{
key: 'key2',
value: {
type: 'Personal',
email: 'user@personal.com'
}
}
]
}
FormModelValidator
getMetaByPath(formModel, path)
Get meta object from formModel
by path string.
getValidatorsByPath(formModel, path)
Get array of validators for given path.
pathIsArray(path)
Returns true if path points to array. Example of path: labels[some_unique_key]
parsePathToArray(path)
Takes path that points to array, and returns object with information about array and array meta.
Example of calling parsePathToArray('labels[key2]')
:
{
itemKey: 'key2', //unique_key_of_array_item'
pathToArray: 'labels', //name_of_array_property_on_form_model
arrayItemIsMeta: true, //true if arrray item is meta object and contains key property
metaPropertyName: null, //name of array item property that contains meta, if arrayItemIsMeta is false
}
Example of calling parsePathToArray('emails[key2].email')
:
{
itemKey: 'key2', //unique_key_of_array_item'
pathToArray: 'emails', //name_of_array_property_on_form_model
arrayItemIsMeta: false, //true if arrray item is meta object and contains key property
metaPropertyName: 'email', //name of array item property that contains meta, if arrayItemIsMeta is false
}
getArrayIndexByKey(formModelArray, key)
Returns index of array item that contains passed unique key
isMetaValid(formModel, path)
Function finds meta by path, and runs validators against meta's value.
If validator returns false, we add message to errors
or warnings
or infos
array depends on the type.
Returns true if meta object is valid.
isModelValid(formModel, stopOnFirstError)
Function takes all validators and validates corresponding meta object in form model.
While validating, errors
, warnings
and infos
properties of each meta is filled of validation messages.
If stopOnFirstError
is set to true (default is false), then validation process stops after first meta object is invalid.
Returns true if form model is valid.
getErrors(formModel)
Function accepts form model and return plain json object with errors, warnings and infos. Example of return value:
{
'name.first': {
errors: ['msg', 'msg'],
warnings: ['msg', 'msg'],
infos: ['msg', 'msg'],
},
'emails[key2].type': {
errors: [ 'msg' ],
warnings: [ 'msg' ],
infos: [ 'msg' ]
},
'emails[key2].email': {
errors: [ 'msg' ],
warnings: [ 'msg' ],
infos: [ 'msg' ]
},
'phones[key2]': {
errors: [ 'msg']
},
'_model': {
errors: ['msg', 'msg'],
warnings: ['msg', 'msg'],
infos: ['msg', 'msg'],
},
}
replaceErrors(formModel, errors)
Function takes errors as argument, and replaces errors/warnings/infos in form model with passed errors object. errors
is an object in following format:
{
'name.first': {
errors: ['msg', 'msg'],
warnings: ['msg', 'msg'],
infos: ['msg', 'msg'],
},
'emails[key2].type': {
errors: [ 'msg' ],
warnings: [ 'msg' ],
infos: [ 'msg' ]
},
'emails[key2].email': {
errors: [ 'msg' ],
warnings: [ 'msg' ],
infos: [ 'msg' ]
},
'phones[key2]': {
errors: [ 'msg']
},
'_model': {
errors: ['msg', 'msg'],
warnings: ['msg', 'msg'],
infos: ['msg', 'msg'],
},
}
objectIsMeta(obj)
Returns true if object has value
of type string
, number
or boolean
.
getOrCreateNestedObjects(json, path)
Function takes json object, and adds nested object by path. Function return deepest object created.
Example:
getOrCreateNestedObjects({}, 'contactInfo.address.city ')
will create following object:
{
contactInfo: {
address: {
}
}
}
Warning: city will not be added as object
getOrCreateNestedArray(json, path)
Function takes json object, and adds array to json. Function returns created array.
Example:
getOrCreateNestedArray({}, 'contactInfo.labels')
will create following object:
{
contactInfo: {
labels: []
}
}
getJSON(formModel)
Function converts form model into json object. Following rules are applied:
First, _model
object is deleted from form model. It is used to display complex validation errors on web page.
Next, form models properties that are arrays, are converted into array on json. Meta properties converted into simple key/value property for json. If form model meta has function that creates custom json, it will be used to create value for json part.
getDoc(formModel, fnTypeConverter)
Function converts form model into json object that will go into database. Following rules are applied:
First, _model
object is deleted from form model. It is used to display complex validation errors on web page.
Next, form models properties that are arrays, are converted into array on json. Meta properties converted into simple key/value property for json. If form model meta has function that creates custom json, it will be used to create value for json part. All keys from arrays are removed.
removeKeysFromArrays(formModelJson)
Removes keys from arrays inside JSON object
hasExistingErrors(formModel)
Function returns true if form model has errors (validators will not be run agains form model field).
createArrayValue(formModel, path, initObject)
Function creates array item based on def
property. New aray item can be initialized using initObject
.
deleteArrayValue(formModel, path, key)
Function deletes array item with specific key
Server helpers
Creating form model
createFormModel
createFormModel(json, fnFormModel, fnPostProcess);
This function accepts json from client and creates form model and returnes json from that form model.
Property | Description |
---|---|
json | JSON that came from client. |
fnFormModel | Form model constructor function. This constructor function accepts json and creates form model with values from that json. Extra properties in json are ignored when building form model. Same constructor function has to be used on the client to create json. |
fnPostProcess | Function that will be called after json is created. This function can be used to modify json. |
Result of this function call:
{
isValid: true|false,
json: {...},
getJSON: () => json,
getDoc: () = > json,
errors: {...},
formModel: {...}
}
isValid
is set to true if after creating form model with json, form model can be successfully validated using fnFormModelValidators
.
json
is JSON object created from form model.
getJSON
function that creates json and returns it.
getDoc
function that creates json with correct types and returns it.
errors
is errors object created by calling FormModelValidator.getErrors(formModel)
is isValid
is false.
formModel
is form model created from json