viewModelFactory
SourceA ViewModel
class is created using the viewModelFactory
function. The factory function is documented immediately below followed by the documentation for the generated class.
Factory
viewModelFactory(fields,options)
Creates a ViewModel class with the specified fields.
const fields = {userId: new IntegerField({ label: 'User ID' })firstName: new CharField({ label: 'First Name' }),// label is optional; will be generated as 'Last name'lastName: new CharField(),};// Options are all optional and can be omitted entirelyconst options = {// Only one of pkFieldName or getImplicitPkField can be defined.// If neither are provided a default field called 'id' will be created.pkFieldName: 'userId',// Multiple names can be specified for compound keyspkFieldName: ['organisationId', 'departmentId']// You can also specify a function to create the primary keygetImplicitPkField(model, fields) {if ('EntityId' in fields) {return ['EntityId', fields.EntityId];}// Generate a name base on model, eg. `userId`const name = model.name[0].toLowerCase() + model.name.slice(1);return [`${name}Id`, new NumberField()];},// Optionally can specify a baseClass for this model. When using `augment`// this is automatically set to the class being augmented.baseClass: BaseViewModel,};class User extends viewModelFactory(fields, options) {// Optional; default cache is usually sufficientstatic cache = new MyCustomCache();// Used to describe a single userstatic label = 'User';// User to describe an indeterminate number of usersstatic labelPlural = 'Users';}
Parameter | Type | Description | |
---|---|---|---|
* | fields | {[ fieldName: string ]: Field} | A map of field name to an instance of |
options.baseClass | Class | Optional base class to extend. This must extend BaseViewModel. When calling | |
* | options.pkFieldName | string|string[] | Primary key name(s) to use. There should be field(s) with the corresponding name in the
provided Only |
ViewModel Class
The class created from viewModelFactory
.
Static Class Methods
augment(newFields,?newOptions)
SourceCreate a new class that extends this class with the additional specified fields. To remove a field that exists on the base class set it's value to null.
class Base extends viewModelFactory({id: new NumberField({label: 'Id',}),firstName: new CharField({label: 'First Name',}),lastName: new CharField({label: 'Last Name',}),email: new EmailField({label: 'Email',}),}) {static label = 'User';static labelPlural = 'Users';}class User extends BaseUser.augment({region: new IntegerField({label: 'region',required: true,helpText: 'Region Coding of the user',choices: [[1, 'Oceania'],[2, 'Asia'],[3, 'Africa'],[4, 'America'],[5, 'Europe'],[6, 'Antarctica'],[7, 'Atlantis'],],}),photo: new ImageField({helpText: 'Will be cropped to 400x400',}),}) {}// trueUser instanceof BaseUser// trueUser.label === 'User'// ['firstName, 'lastName', 'email', 'region', 'photo]User.fieldNames
Parameter | Type | Description | |
---|---|---|---|
* | newFields | FieldsMappingOrNull | Map of field name to a |
newOptions | Partial | Provide optional overrides for the options that the original class was created with |
A new ViewModel class with fields modified according to newFields
.
getField(fieldName)
SourceGet a field from this model or a related model
Accepts either a string for a field on this record or array notation for traversing RelatedViewModelField fields:
Subscription.getField(['user', 'group', 'owner'])
Parameter | Type | Description | |
---|---|---|---|
* | fieldName | FieldPath | Either a string or an array of strings where the last element is the final field name to return and each other element is a RelatedViewModelField on a ViewModel. |
Static Class Properties
allFieldNames: string[]
Shortcut to get all field names including primary keys
cache: ViewModelCache
The cache instance for this ViewModel. A default instance of ViewModelCache is created when first accessed or you can explicitly assign a cache:
class User extends viewModelFactory(fields) {static cache = new MyCustomCache(User);}
fieldNames: string[]
Shortcut to get the names of all fields excluding primary keys.
If you want all fields including primary key use allFieldNames
fields: {[ fieldName: string ]: Field}
The bound fields for this ViewModel. These will match the fields
passed in to ViewModel
with the
following differences:
- If a primary key is created for you this will exist here
- All fields are bound to the created class. This means you can access the
ViewModel
class from the field on themodel
property, eg.User.fields.email.model === User
will be true. - All fields have the
name
property set to match the key infields
- All fields have
label
filled out if not explicitly set (eg. if name wasemailAddress
label will be created asEmail Address
)
See also getField for getting a nested field using array notation.
label: string
The singular label for this ViewModel. This should be set by extending the created class.
class User extends viewModelFactory(fields) {static label = 'User';}
labelPlural: string
The label used to describe an indeterminate number of this ViewModel. This should be set by extending the created class.
class User extends viewModelFactory(fields) {static labelPlural = 'Users';}
pkFieldName: string
Name of the primary key field for this ViewModel (or fields for compound keys)
If options.pkFieldName
is not specified a field will be created from options.getImplicitPk
if provided otherwise a default field with name 'id' will be created.
pkFieldNames: string[]
Shortcut to get pkFieldName as an array always, even for non-compound keys
relationFieldNames: string[]
Shortcut to get the names of all relation fields
Instance Methods
clone(?fieldNames)
SourceClone this record, optionally with only a subset of the fields
Parameter | Type | Description | |
---|---|---|---|
fieldNames | string[]|FieldPath[] |
fieldPathIntersection(records)
SourceGiven records
return the paths that are common between them.
A naive solution is to just check _assignedFieldsDeep
:
const paths = intersectionBy(...assignedData[key].map(record => record._assignedFieldsDeep),p => flattenFieldPath(p).join('|'));
but that would fail if some records had a null value for a relation and others didn't.
This function handles nested records such that a null relation is ignored. For example if you received:
[{id: 1,nestedRecordId: null,nestedRecord: null,},{id: 2,nestedRecordId: 1,nestedRecord: {id: 1,name: 'Nested Record 1',},},{id: 3,nestedRecordId: 2,nestedRecord: {id: 2,name: 'Nested Record 2',otherField: 'Name',},}]
would result in
['id', 'nestedRecordId', ['nestedRecord', 'id'], ['nestedRecord', 'name']]
Noting that the first record has no nested fields (because they are null) and so get's ignored, and the last record has 'otherField' which the second doesn't so is excluded.
Parameter | Type | Description | |
---|---|---|---|
* | records | ViewModelInterface[] |
isEqual(record)
SourceCompares two records to see if they are equivalent.
- If the ViewModel is different then the records are always considered different
- If the records were initialised with a different set of fields then they are considered different even if the common fields are the same and other fields are all null
Parameter | Type | Description | |
---|---|---|---|
* | record | ViewModelInterface|null |
Instance Properties
_assignedFieldPaths: ViewModelFieldPaths
The ViewModelFieldPaths
instance for this record. This is a unique instance based on the actual
assigned fields and can be compared to other instances to determine if the same fields are set.
_assignedFields: string[]
List of field names with data available on this instance.
_assignedFieldsDeep: string[]
Deep field names set on this record. If no relations are set this is the same as _assignedFields
.
A deep field is a field that is a relation to another model and is represented as an array, eg.
['group', 'name']
would be the the name
field on the group
relation.
_data: Object
The assigned data for this record. You usually don't need to access this directly; values for a field can be retrieved from the record directly using the field name
_f: {[fieldName: string]: Field}
Get fields bound to this record instance. Each field behaves the same as accessing it via ViewModel.fields but
has a value
property that contains the value for that field on this record.
This is useful when you need to know both the field on the ViewModel and the value on a record (eg. when formatting a value from a record
const user = new User({ name: 'Jon Snow' });user.name// Jon Snowuser._f.name// CharField({ name: 'name', label: 'Label' });user._f.name.value// Jon Snow
_key: PkFieldType
Returns the primary key value(s) for this instance. This is to conform to the Identifiable interface.
_model: ViewModel Class
Get the actual ViewModel class for this instance