Model

A Model is the definition of a record which can be added to (or loaded into) a Store. It defines which fields the data contains and exposes an interface to access and manipulate that data. The Model data is populated through simple a JSON object.

By default, a Model stores a shallow copy of its raw json, but for records in stores configured with useRawData: true it stores the supplied json object as is.

Defining fields

A Model can either define its fields explicitly (see fields) or have them created from its data (see autoExposeFields). This snippet shows a model with 4 fields defined explicitly:

class Person extends Model {
    static fields = [
        'name',
        { name : 'birthday', type : 'date', format : 'YYYY-MM-DD' },
        { name : 'shoeSize', type : 'number', defaultValue : 11 },
        { name : 'age', readOnly : true }
    ]
}

The first field (name) has an unspecified type, which means the field's value is held as received with no conversion applied. The second field (birthday) is defined to be a date, which will make the model parse any supplied value into an actual date. The parsing is handled by DateHelper.parse() using the specified format, or if no format is specified using DateHelper.defaultFormat.

While defining fields on Model in TypeScript, data fields should be of type ModelFieldConfig instead of DataField, because it is a union type that gives completion based on specified type.

class Person extends Model {
    static fields: ModelFieldConfig[] = [
        'name',
        { name : 'birthday', type : 'date', format : 'YYYY-MM-DD' },
        { name : 'shoeSize', type : 'number', defaultValue : 11 },
        { name : 'age', readOnly : true }
    ]
}

The set of standard field types is as follows:

You can also set a defaultValue that will be used if the data does not contain a value for the field:

{ name : 'shoeSize', type : 'number', defaultValue : 11 }

Defining a field with a name containing a . will by default point to a nested object in the data. If you have a data property that actually contains a . in the name, also configure complexMapping : false on the field:

class Organization extends Model {
    static fields = [
        // Points to { "org" : { "name" : "..." } } in the data
        { name : 'org.name' },
        // Points to { "org.address" : "..." } in the data
        { name : 'org.address', complexMapping : false }
    ]
}

Creating a record

To create a record from a Model, supply data to its constructor:

const guy = new Person({
    id       : 1,
    name     : 'Dude',
    birthday : '2014-09-01'
});

If no id is specified, a temporary id based on a UUID will be generated. This id is not meant to be serialized, it should instead be replaced by the backend with a proper id from the underlying database (or similar).

Please avoid using reserved names for your fields (such as parent, children and others that are used as Model properties) to avoid possible data collisions and bugs.

When adding data to a Store, you do normally not need to create records manually. The store does that for you when you add a data object to it

Calculated fields

A field value can also be calculated using the other data fields, using the calculate config.

const store = new Store({
    fields : [
        { name : 'revenue', type : 'number' },
        { name : 'tax', type : 'number' },
        { name : 'net', calculate : record => record.revenue * (1 - (record.tax / 100)) }
    ],
    data : [
        { id : 1, revenue : 100, tax : 30 }
    ]
});

const record = store.getById(1).net; // 70

Nested fields

Model supports mapping fields to nested data structures using dot . separated paths as the dataSource. For example given this JSON object:

{
    name : 'Borje Salming',
    team : {
        name   : 'Toronto Maple Leafs',
        league : 'NHL'
    }
}

A field can be mapped to the nested team name by using dataSource : 'team.name':

class Player extends Model {
    static fields = [
        'name',
        // Field mapped to a property on a nested object
        { name : 'teamName', dataSource : 'team.name' }
    ];
}

Usage:

const player = new Player(json);

console.log(player.teamName); // > Toronto Maple Leafs
player.teamName = 'Minnesota Wild'; // Updates name property of the team object

Alternatively, you can define the top level of the nested object as a field of type object:

class Person extends Model {
    static fields = [
        'name',
        // Nested object
        { name : 'address', type : 'object' }
    ];
}

You can then access properties of the nested object using dot notation with the get function:

const person = new Person({
   name    : 'Borje Salming',
   address : {
       city : 'Toronto'
   }
});

person.get('address.city'); // > Toronto

Updating a nested object

Note that directly altering a property of the nested object won't register as an update of the record, record does not track changes deeply. If nested fields (as described above) is not enough for your usecase you can map a field directly to the nested object and then assign a shallow copy of it to the record on changes:

class Player extends Model {
    static get fields() {
        return [
            ...,
            // Field mapped directly to the nested object
            { name : 'team', type : 'object' }
        ]
    }
}

// "External object" to nest
const team = {
    name   : 'Brynas',
    league : 'SHL'
}

const player = new Player({
    name : 'Borje Salming',
    team
});

// This will not flag player as dirty
team.league = 'CHL';

// Instead you have to reassign the mapped field
player.team = { ...player.team };

You can also use the set function to update a property of the nested object:

// This will flag player as dirty
player.set('team.name', 'BIF');

Arrays of atomic types

When a field holds an array of atomic types (strings, numbers etc.) we recommend using the array type for the field:

class GroceryList extends Model {
    static get fields() {
        return [
            'name',
            { name : 'items', type : 'array' }
        ];
    }
}

const list = new GroceryList({
   name  : 'My list',
   items : ['Milk', 'Bread', 'Eggs']
});

Modifying items in the array will not flag the field as updated, since the array itself does not change. For it to register a change, you must assign it a new array (could be a copy of the old one). For more info, see ArrayDataField

Arrays of objects

When a field holds an array of objects, we recommend using the store type for the field:

class GroceryList extends Model {
    static fields = [
        'name',
        { name : 'items', type : 'store', storeClass : Store }
    ]
}

const list = new GroceryList({
   name  : 'My list',
   items : [
       { name : 'Milk', quantity : 1 },
       { name : 'Bread', quantity : 2 },
       { name : 'Eggs', quantity : 12 }
   ]
});

The items field on the list above will be a Store instance (because we passed that as storeClass), which can be used to manipulate the items in the list. Doing so will flag the list as modified. For more info, see StoreDataField.

Persisting fields

By default, all fields are persisted. If you don't want particular field to get saved to the server, configure it with persist: false. In this case field will not be among changes which are sent by store.commit(), otherwise its behavior doesn't change.

class Person extends Model {
    static get fields() {
        return [
            'name',
            { name : 'age', persist : false }
        ];
    }
}

The id field

By default Model expects its id field to be stored in a data source named "id". The data source for the id field can be customized by setting dataSource on the id field object configuration.

class Person extends Model {
    static fields = [
        { name : 'id', dataSource: 'personId'},
        'name',
        { name : 'age', persist : false },
        { name : 'birthday', type : 'date' }
     ];
}

let girl = new Person({
    personId : 2,
    name     : 'Lady',
    birthday : '2011-11-05'
});

Also, it is possible to change the id field data source by setting idField:

class Person extends Model {
    // Id drawn from 'id' property by default; use custom field here
    static idField = 'personId';

    static fields = [
        'name',
        { name : 'age', persist : false },
        { name : 'birthday', type : 'date' }
    ];
}

Getting and setting values

Fields are used to generate getters and setters on the records. Use them to access or modify values (they are reactive):

console.log(guy.name);
girl.birthday = new Date(2011,10,6);

NOTE: In an application with multiple different models you should subclass Model, since the prototype is decorated with getters and setters. Otherwise, you might get unforeseen collisions.

Field data mapping

By default, fields are mapped to data using their name. If you for example have a "name" field it expects data to be { name: 'Some name' }. If you need to map it to some other property, specify dataSource in your field definition:

class Person extends Model {
    static fields = [
        { name : 'name', dataSource : 'TheName' }
    ];
}

// This is now OK:
let dude = new Person({ TheName : 'Manfred' });
console.log(dude.name); // --> Manfred

NOTE: Do not modify fields using dataSource, as it is intended only for reading and writing from the raw data object. Fields should be modified using name as it is the public interface.

Field inheritance

Fields declared in a derived model class are added to those from its superclass. If a field declared by a derived class has also been declared by its super class, the field properties of the super class are merged with those of the derived class.

For example:

 class Person extends Model {
     static fields = [
         'name',
         { name : 'birthday', type : 'date', format : 'YYYY-MM-DD' }
     ];
 }

 class User extends Person {
     static fields = [
         { name : 'birthday', dataSource : 'dob' },
         { name : 'lastLogin', type : 'date' }
     ];
 }

In the above, the Person model declares the birthday field as a date with a specified format. The User model extends Person and also declares the birthday field. This redeclared field only specifies dataSource, so all the other fields are preserved from Person. The User model also adds a lastLogin field.

Note that later accessing Person.fields will refer to the block of two fields defined above (birthday & lastLogin), not to all fields available (name, birthday, lastLogin). To access all fields, use allFields on the Model class instead, or the fields property on a record (instance).

The User from above could have been declared like so to achieve the same fields:

 class User extends Model {
     static fields = [
         'name',
         { name : 'birthday', type : 'date', format : 'YYYY-MM-DD', dataSource : 'dob' },
         { name : 'lastLogin', type : 'date' }
     ];
 }

Override default values

In case you need to define default value for a specific field, or override an existing default value, you can define a new or re-define an existing field definition in fields static getter:

class Person extends Model {
    static fields = [
        { name : 'username', defaultValue : 'New person' },
        { name : 'birthdate', type : 'date' }
    ];
}

class Bot extends Person {
    static fields = [
        { name : 'username', defaultValue : 'Bot' } // default value of 'username' field is overridden
    ];
}

Read-only records

Model has a default field called readOnly, which is used to make the record read-only in the UI while still allowing programmatic changes to it. Setting it to true will prevent it from being edited by the built-in editing features (cell editing in Grid, event dragging in Scheduler, task editor in Gantt etc.). Please note that it is not made read-only on the data level, the record can still be manipulated by application code.

// Prevent record from being manipulated by the user
record.readOnly = true;

// Programmatic manipulation is still allowed
record.remove();

Tree API

This class mixes in the TreeNode mixin which provides an API for tree related functionality (only relevant if your store is configured to be a tree).

Properties

66

Class hierarchy

isModel: Boolean= truereadonly
Identifies an object as an instance of Model class, or subclass thereof.
isModel: Boolean= truereadonlystatic
Identifies an object as an instance of Model class, or subclass thereof.
isModelStm: Boolean= truereadonlyModelStm
Identifies an object as an instance of ModelStm class, or subclass thereof.
isModelStm: Boolean= truereadonlystaticModelStm
Identifies an object as an instance of ModelStm class, or subclass thereof.
isTreeNodeTreeNode

Editing

copyOf: Modelreadonly

For copied records, this property links to the original model instance from which it was copied.

isBatchUpdating: Booleanreadonly

True if this Model is currently batching its changes.

isCommitting: Boolean

True if this models changes are currently being committed.

isCreating: Boolean

Set this property to true when adding a record on a conditional basis, that is, it is yet to be confirmed as an addition.

When this is set, the isPersistable value of the record is false, and upon being added to a Store it will not be eligible to be synced with the server as an added record.

Subsequently, clearing this property means this record will become persistable and eligible for syncing as an added record.

isModified: Booleanreadonly

True if this model has any uncommitted changes.

isValid: Boolean

Check if record has valid data. Default implementation returns true, override in your model to do actual validation.

modificationData: Objectreadonly

Get a map of the modified fields in form of an object. The field´s dataSource is used as the property name in the returned object. The record´s id is always included.

modificationDataToWrite: Objectreadonly

Get a map of the modified data fields along with any alwaysWrite fields, in form of an object. The field´s dataSource is used as the property name in the returned object. Used internally by AjaxStore / CrudManager when sending updates.

modifications: Objectreadonly

Get a map of the modified fields in form of an object. The field names are used as the property names in the returned object, and the property values are the latest field values.

The id field is always included.

Fields

allFields: DataField[]readonlystatic

An array containing all the defined fields for this Model class. This will include all superclass's defined fields.

allFields: DataField[]readonly

Same as allFields.

autoExposeFields: Booleanstatic

Flag checked from Store when loading data that determines if fields found in first records should be exposed in same way as predefined fields.

Note that we for all but the most basic use cases recommend explicitly defining the fields. Having them auto exposed can lead to unexpected behavior, if the first record is not complete (fields missing, null etc).

childrenField: Stringstatic

The name of the data field which holds children of this Model when used in a tree structure

MyModel.childrenField = 'kids';
const parent = new MyModel({
    name : 'Dad',
    kids : [
        { name : 'Daughter' },
        { name : 'Son' }
    ]
});
classDisplayName: Stringreadonly

Returns the string value for display purposes of an instance of this Model class. Needs to be overridden in subclasses.

defaults: Objectstatic

Template static getter which is supposed to be overridden to define default field values for the Model class. Overrides defaultValue config specified by the fields getter. Returns a named object where key is a field name and value is a default value for the field.

NOTE: This is a legacy way of defining default values, we recommend using fields moving forward.

class Person extends Model {
    static get fields() {
        return [
            { name : 'username', defaultValue : 'New person' }
        ];
    }
}

class Bot extends Person {
    static get defaults() {
        return {
            username : 'Bot' // default value of 'username' field is overridden
        };
    }
}
fieldMap: Object<String, DataField>readonlystatic

An object containing all the defined fields for this Model class. This will include all superclass's defined fields through its prototype chain. So be aware that Object.keys and Object.entries will only access this class's defined fields.

fieldMap: Object<String, DataField>readonly

Same as fieldMap.

fieldNames: String[]readonly

Get the names of all properties in the data object.

Note that this is not the same as the fields defined for the model, in most cases you probably want to use fields instead.

fields: (String|ModelFieldConfig|DataField)[]readonlystatic

Array of defined fields for this model class. Subclasses add new fields by implementing this static getter:

// Model defining two fields
class Person extends Model {
    static get fields() {
        return [
            { name : 'username', defaultValue : 'New person' },
            { name : 'birthdate', type : 'date' }
        ];
    }
}

// Subclass overriding one of the fields
class Bot extends Person {
    static get fields() {
        return [
            // Default value of 'username' field is overridden, any other setting from the parents
            // definition is preserved
            { name : 'username', defaultValue : 'Bot' }
        ];
    }
}

Fields in a subclass are merged with those from the parent class, making it easy to override mappings, formats etc.

Note that later accessing Bot.fields will refer to the block with the redefinition of the username field seen above, not to all fields available (username, birthdate). To access all fields, use either allFields on the Model class, or the fields property on a record.

fields: DataField[]readonly

Convenience getter to get field definitions from class.

idField: Stringstatic

The data source for the id field which provides the ID of instances of this Model.

Grouping

groupChildren: Model[] | undefinedreadonly

When called on a group header row returns list of records in that group. Returns undefined otherwise.

isGroupHeader: Booleanreadonly

Returns true for a group header record

Identification

generatedParent: Booleanreadonly

Reports true when the record is a parent record generated by the TreeGroup feature.

Only valid for stores used with TreeGroup feature enabled.

Checks if record has a generated id.

New records are assigned a generated id based on a UUID (starting with _generated), which is intended to be temporary and should be replaced by the backend on commit.

internalId: Number

Gets the records internalId. It is assigned during creation, guaranteed to be globally unique among models.

isPhantom: Booleanreadonly

Returns true if the record is new and has not been persisted (and received a proper id).

key: *readonly

Holds the value that a generated group parent represents when using the TreeGroup feature.

Only valid for stores used with TreeGroup feature.

JSON

json: String

Get the records data as a json string.

const record = new Model({
    title    : 'Hello',
    children : [
        ...
    ]
});

const jsonString = record.json;

//jsonString:
'{"title":"Hello","children":[...]}'

Linked records

isLinked: BooleanreadonlyModelLink

Is this record linked to another record?

Get the original record this record is linked to.

Misc

firstStore: Storereadonly

Get the first store that this model is assigned to.

Reference to STM manager, if used

Other

$name: Stringstatic

Class name getter. Used when original ES6 class name is minified or mangled during production build. Should be overridden in each class which extends Model or it descendants.

class MyNewClass extends Model {
    static $name = 'MyNewClass';
}
isPersistable: Booleanreadonly

This yields true if this record is eligible for syncing with the server. It can yield false if the record is in the middle of a batched update, or if it is a tentative record yet to be confirmed as a new addition.

relations: Object<String, RelationConfig>static

Override in a subclass of Model to define relations to records in other stores.

Always defined on the "one" side, not the "many" side.

Expects an object where keys are relation names and values are relation configs.

This snippet will define a relation called team, allowing access to the foreign record via player.team. It will point to a record in the teamStore (must be available as record.firstStore.teamStore) with an id matching the players teamId field. The team record in turn, will have a field called players which is a collection of all players in the team.

class Player extends Model {
    static relations = {
        // Define a relation between a player and a team
        team : {
            foreignKey            : 'teamId',
            foreignStore          : 'teamStore',
            relatedCollectionName : 'players'
        }
    }
}

const teamStore = new Store({
    data : [
        { id : 1, name : 'Brynas' },
        { id : 2, name : 'Leksand' }
    ]
});

const playerStore = new Store({
    modelClass : Player,
    // Matches foreignStore, allowing records of playerStore to find the related store
    teamStore,
    data       : [
        // teamId is specified as foreignKey, will be used to match the team
        { id : 1, name : 'Nicklas Backstrom', teamId : 1  },
        { id : 2, name : 'Elias Lindholm',   teamId : 1  },
        { id : 3, name : 'Filip Forsberg',  teamId : 2  }
    ],
}

playerStore.first.team.name // > Brynas
playerStore.last.team.name // > Leksand
teamStore.first.players // > [nick, elias]
teamStore.last.players // > [filip]

To access the related record from the many side, use dot notation for the field name. For example in a Grid column:

const grid = new Grid({
   store : playerStore,
   columns : [
       { field : 'name', text : 'Name' },
       { field : 'team.name', text : 'Team' }
   ]
});

Lifecycle

configBase

Parent & children

allChildrenTreeNode
childLevelTreeNode
firstChildTreeNode
isLeafTreeNode
isLoadedTreeNode
isParentTreeNode
isRootTreeNode
lastChildTreeNode
nextSiblingTreeNode
parentTreeNode
parentIdTreeNode

Functions

56

Editing

Begin a batch, which stores changes and commits them when the batch ends. Prevents events from being fired during batch.

record.beginBatch();
record.name = 'Mr Smith';
record.team = 'Golden Knights';
record.endBatch();

Please note that you can also set multiple fields in a single call using set, which in many cases can replace using a batch:

record.set({
  name : 'Mr Smith',
  team : 'Golden Knights'
});

Cancels current batch operation. Any changes during the batch are discarded.

Clears tracked changes, used on commit. Does not revert changes.

ParameterTypeDescription
includeDescendantsBoolean

Supply false to not clear node descendants

Makes a copy of this model, assigning the specified id or a generated id and also allowing you to pass field values to the created copy. A copyOf property is set on the copy to reference the original record.

const record = new Model({ name : 'Super model', hairColor : 'Brown' });
const clone = record.copy({ name : 'Super model clone' });
ParameterTypeDescription
newIdOrDataNumber | String | Object

The id for the copied instance, or any field values to apply (overriding the values from the source record). If no id provided, one will be auto-generated

deepBoolean

True to also clone children

Returns: Model -

Copy of this model

End a batch, triggering events if data has changed.

ParameterTypeDescription
silentBoolean

Specify true to not trigger events. If event is recurring, occurrences won't be updated automatically.

Returns raw data from the encapsulated data object for the passed field name

ParameterTypeDescription
fieldNameString

The field to get data for.

Returns: * -

The raw data value for the field.

Returns the unmodified value of the field, as in the value it had after the last commit. If the field has not been modified, the current value is returned.

ParameterTypeDescription
fieldNameString

Field name

Returns: * -

The unmodified value of the field, or its current value if not modified

Returns true if this Model currently has outstanding batched changes for the specified field name.

ParameterTypeDescription
fieldNameString

The field name to check for batched updates on.

Returns: Boolean

Returns true if this model has uncommitted changes for the provided field.

ParameterTypeDescription
fieldNameString

Field name

Returns: Boolean -

true if the field has an uncommitted change

Removes this record from all stores (and in a tree structure, also from its parent if it has one).

ParameterTypeDescription
silentBoolean

Specify true to not trigger events. If the event is recurring, occurrences won't be updated automatically.

Reverts changes in this back to their original values.

Set value for the specified field. You can also use the generated setters if loading through a Store.

Setting a single field, supplying name and value:

record.set('name', 'Clark');

Setting multiple fields, supplying an object:

record.set({
    name : 'Clark',
    city : 'Metropolis'
});

NOTE: Do not modify fields using dataSource, as it is intended only for reading and writing from the raw data object. Fields should be modified using name as it is the public interface.

ParameterTypeDescription
fieldString | Object

The field to set value for, or an object with multiple values to set in one call

value*

Value to set

silentBoolean

Set to true to not trigger events. If event is recurring, occurrences won't be updated automatically.

Fields

addFieldstatic

Add a field definition in addition to those predefined in fields.

ParameterTypeDescription
fieldDefString | ModelFieldConfig

A field name or definition

Returns: DataField

Get value for specified field name. You can also use the generated getters if loading through a Store. If model is currently in batch operation this will return updated batch values which are not applied to Model until endBatch() is called.

ParameterTypeDescription
fieldNameString

Field name to get value from

Returns: * -

Fields value

Get the data source used by specified field. Returns the fieldName if no data source specified.

ParameterTypeDescription
fieldNameString

Field name

Returns: String

Convenience function to get the definition for a field from class.

ParameterTypeDescription
fieldNameString

Field name

Returns: DataField

Get the definition for a field by name.

ParameterTypeDescription
fieldNameString

Field name

Returns: DataField -

Field definition or null if none found

Processes input to a field, converting to expected type.

ParameterTypeDescription
fieldNameString

Field name

value*

Value to process

Returns: * -

Converted value

Remove a field definition by name.

ParameterTypeDescription
fieldNameString

Field name

Identification

asIdstatic

Gets the id of specified model or model data object, or the value if passed string/number.

ParameterTypeDescription
modelModel | String | Number
Returns: String | Number -

id

Generates an id for a new record (a phantom id), based on a UUID by default.

This function can be overridden to provide custom id generation logic.

let idCounter = 0;
// Override the default logic with app specific
Model.generateId = () => `id${new Date().getTime()}${idCounter++}`;
ParameterTypeDescription
textString

Text used as optional prefix for the id, defaults to the name of the class

Returns: String | Number -

A generated id

Generates an id for a new record (a phantom id), based on a UUID (starting with _generated).

Generated ids are intended to be temporary and should be replaced by the backend on commit.

Returns: String

JSON

Used by JSON.stringify() to correctly convert this record to json.

In most cases no point in calling it directly.

// This will call `toJSON()`
const json = JSON.stringify(record);

If called manually, the resulting object is a clone of record.data + the data of any children:

const record = new Model({
    title    : 'Hello',
    children : [
        ...
    ]
});

const jsonObject = record.toJSON();

// jsonObject:
{
    title : 'Hello',
    children : [
        ...
    ]
}
Returns: Object

Represent the record as a string, by default as a JSON string. Tries to use an abbreviated version of the object's data, using id + name/title/text/label/description. If no such field exists, the full data is used.

const record = new Model({ id : 1, name : 'Steve Rogers', alias : 'Captain America' });
console.log(record.toString()); // logs { "id" : 1, "name" : "Steve Rogers" }
Returns: String

Lifecycle

Constructs a new record from the supplied data config.

ParameterTypeDescription
configObject

Raw model config

storeStore

Data store

metaObject

Meta data

destroystaticBase

Misc

Compares this Model instance to the passed instance. If they are of the same type, and all fields (except, obviously, id) are equal, this returns true.

ParameterTypeDescription
otherModel

The record to compare this record with.

Returns: Boolean -

true if the other is of the same class and has all fields equal.

initClassstaticBase
isOfTypeNamestaticBase
mixinstaticBase

Other

Defines if the given event field should be manually editable in UI. You can override this method to provide your own logic.

ParameterTypeDescription
fieldNameString

Name of the field

Returns: Boolean | undefined -

Returns true if the field is editable, false if it is not and undefined if the model has no such field.

Configuration

applyDefaultsstaticBase

Events

Parent & children

appendChildTreeNode
bubbleTreeNode
bubbleWhileTreeNode
containsTreeNode
insertChildTreeNode
isExpandedTreeNode
removeChildTreeNode
traverseTreeNode

Typedefs

1

Defines the properties of a relation between two stores.

Used as the values of a Model's relations definition.

This snippet will define a relation called team, allowing access to the foreign record via player.team. It will point to a record in the teamStore (must be available as record.firstStore.teamStore) with an id matching the players teamId field. The team record in turn, will have a field called players which is a collection of all players in the team.

class Player extends Model {
    static relations = {
        team : {
            foreignKey            : 'teamId',
            foreignStore          : 'teamStore',
            relatedCollectionName : 'players'
        }
    }
}

See relations for a more extensive example.

ParameterTypeDescription
foreignKeyString

Name of a field on this model which holds the foreign key value.

foreignStoreString | Store

Name of a property on the model's first store, which holds the foreign store. Or the actual store instance

relatedCollectionNameString

Optionally, name of a property that will be added to the records of the foreign store, which will hold all records from the model's store related to it.

propagateRecordChangesBoolean

Set to true to propagate record changes (add, remove, update) to the related records stores. The related stores will in turn trigger an update event which makes it possible for the UI to react.

Fields

3

Common

id: String | Number

Unique identifier for the record. Might be mapped to another dataSource using idField, but always exposed as record.id. Will get a generated value if none is specified in records data.

Note that generated ids are meant to be temporary (phantom ids), they should not be serialized but instead replaced by the backend on commit

readOnly: Boolean

Flag the record as read-only on the UI level, preventing the end user from manipulating it using editing features such as cell editing and event dragging.

Does not prevent altering the record programmatically, it can still be manipulated by application code.

For more info, see the "Read-only records" section above.

Tree

expanded: Booleanreadonly

Start expanded or not (only valid for tree data)