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
ViewModelclass from the field on themodelproperty, eg.User.fields.email.model === Userwill be true. - All fields have the
nameproperty set to match the key infields - All fields have
labelfilled out if not explicitly set (eg. if name wasemailAddresslabel 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