viewModelFactory

Source
import { viewModelFactory } from "@prestojs/viewmodel";

A ViewModel class is created using the viewModelFactory function. The factory function is documented immediately below followed by the documentation for the generated class.

Factory

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 entirely
const 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 keys
pkFieldName: ['organisationId', 'departmentId']
// You can also specify a function to create the primary key
getImplicitPkField(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 sufficient
static cache = new MyCustomCache();
// Used to describe a single user
static label = 'User';
// User to describe an indeterminate number of users
static labelPlural = 'Users';
}
ParameterTypeDescription
*fields{[ fieldName: string ]: Field}

A map of field name to an instance of Field

options.baseClassClass

Optional base class to extend. When calling augment this is set the augmented class.

options.getImplicitPkFieldFunction

A function to generate field(s) to use for the primary key. It is passed the model class and the fields on the model. It should return an array of size 2 - first element should be the field name and the second an instance of Field.

options.pkFieldNamestring|string[]

Primary key name(s) to use. There should be field(s) with the corresponding name in the provided fields.

Only pkFieldName or getImplicitPkField should be provided. If neither are provided then a field called id will be used and created if not provided in fields.

ViewModel Class

ViewModel Class

The class created from viewModelFactory.

Static Class Methods

Create 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',
}),
}) {
}
// true
User instanceof BaseUser
// true
User.label === 'User'
// ['firstName, 'lastName', 'email', 'region', 'photo]
User.fieldNames
ParameterTypeDescription
*newFields{[ fieldName: string ]: Field|null}

Map of field name to a Field instance (to add the field) or null (to remove the field)

newOptions.baseClassClass

Optional base class to extend. When calling augment this is set the augmented class.

newOptions.getImplicitPkFieldFunction

A function to generate field(s) to use for the primary key. It is passed the model class and the fields on the model. It should return an array of size 2 - first element should be the field name and the second an instance of Field.

newOptions.pkFieldNamestring|string[]

Primary key name(s) to use. There should be field(s) with the corresponding name in the provided fields.

Only pkFieldName or getImplicitPkField should be provided. If neither are provided then a field called id will be used and created if not provided in fields.

ViewModel Class

A new ViewModel class with fields modified according to newFields.

Get 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'])
ParameterTypeDescription
*fieldNameFieldPath

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.

Field

Static Class Properties

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);
}

Shortcut to get the names of all fields excluding primary keys.

If you want all fields including primary key do:

model.fieldNames.concat(model.pkFieldNames);

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 the model property, eg. User.fields.email.model === User will be true.
  • All fields have the name property set to match the key in fields
  • All fields have label filled out if not explicitly set (eg. if name was emailAddress label will be created as Email Address)

See also getField for getting a nested field using array notation.

The singular label for this ViewModel. This should be set by extending the created class.

class User extends viewModelFactory(fields) {
static label = 'User';
}

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';
}

Name of the primary key field for this 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.

Shortcut to get pkFieldName as an array always, even for non-compound keys

Instance Methods

Clone this record, optionally with only a subset of the fields

ParameterTypeDescription
fieldNames
ViewModel
ParameterTypeDescription
fieldNamesFieldPath[]
ViewModel

Compares 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
ParameterTypeDescription
*recordViewModel|null
boolean

Return the data for this record as an object

FieldDataMapping

Instance Properties

List of field names with data available on this instance.

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

Access record bound fields. A record bound field is a normal field with it's value property set to the corresponding value for that field on the record. This is useful as a shortcut to get both the field and it's value.

class User extends viewModelFactory({ username: CharField() }) {}
const admin = new User({ id: 1, username: 'admin' });
// true
admin._f.username instanceof CharField();
admin._f.username.value === 'admin'

Returns the primary key value(s) for this instance. This is to conform to the Identifiable interface.

Get the actual ViewModel class for this instance