Paths
The model’s data can be thought of as a JSON object tree.
A path is a string with dot-separated segments, referring to a node (sub-object or value) within the tree. Each segment represents a property lookup within an object or array. Array indexes are 0-based like in JavaScript.
For example, the model data:
{
_page: {
currentStorefrontId: 'storefront-1',
},
storefronts: {
'storefront-a': {
id: 'storefront-a',
title: 'Fruit store',
fruits: [
{ name: 'banana', color: 'yellow' },
{ name: 'apple', color: 'red' },
{ name: 'lime', color: 'green' }
]
}
}
}
Would have paths like:
'_page'
, referring to the object{ currentStorefrontId: 'storefront-1' }
'storefronts.storefront-a.title'
, referring to the title of “storefront-a”'storefronts.storefront-a.fruits.0'
, referring to the first fruit object in “storefront-a”
From the data root, the first level of properties are collection names, in this case '_page'
and 'storefront-a'
. These can have special meanings, as described in the next section.
WARNING If you want to use a number as a path segment, be careful to prefix this before setting it. Otherwise, you will accidentally create a gigantic array and probably run out of memory. For example, use a path like:
items.id_1239182389123.name
and neveritems.1239182389123.name
.
Local and remote collections
Collection names (i.e. the first path segment) that start with an underscore (_
) are local and are not synced to the database. Data written to local collections during server-side rendering is available in the browser, but that data isn’t shared with other servers or clients.
Collection names that begin with dollar signs ($
) are special local collections reserved for use by Racer, Derby, or extensions, and should not be used for application data.
Collection names not prefixed with those special characters are considered remote collections, and will be synced to the server and other clients via ShareDB.
Almost all non-synced data within an application should be stored underneath the _page
local collection, which Derby to automatically cleans up when the user navigates between pages. Right before rendering a new page, Derby calls model.destroy('_page')
, which removes all data, references, event listeners, and reactive functions underneath the _page
collection.
If you have some local data that you would like to be maintained between page renders, it can be stored underneath a different local collection. This is useful for setting data on the server, such as setting _session.userId
in authentication code. However, be very careful when storing local data outside of _page
, since bleeding state between pages is likely to be a source of unexpected bugs.
Scoped models
Scoped models provide a more convenient way to interact with commonly used paths. They support the same methods, and they provide the path argument to accessors, mutators, event methods, and subscription methods. Also, wherever a path is accepted in a racer method, a scoped model can typically be used as well.
scoped = model.at(subpath)
subpath
A relative path starting from the current model’s pathscoped
Returns a scoped model
scoped = model.scope([absolutePath])
absolutePath
(optional) An absolute path from the root of the model data, or the root path by default. This will become the scope even if called on a scoped model. May be called without a path to get a model scoped to the rootscoped
Returns a scoped model
scoped = model.parent([levels])
levels
(optional) Defaults to 1. The number of path segments to remove from the end of the reference pathscoped
Returns a scoped model
path = model.path([subpath])
subpath
(optional) A relative reference path to append. Defaults to the current pathpath
Returns the reference path if applicable
isPath = model.isPath(subpath)
subpath
A relative reference path or scoped modelisPath
Returns true if the argument can be interpreted as a path, false otherwise
segment = model.leaf()
segment
Returns the last segment for the reference path. Useful for getting indices, ids, or other properties set at the end of a path
const roomModel = model.at('_page.room');
// These are equivalent:
roomModel.at('name').set('Fun room');
roomModel.set('name', 'Fun room');
// Logs: {name: 'Fun room'}
console.log(roomModel.get());
// Logs: 'Fun room'
console.log(roomModel.get('name'));
// Use model.scope(absolutePath) to refer to things outside a model's subtree.
class MyComponent extends Component {
init() {
// In a component, `this.model` is the component's "private" scoped model
const roomModel = this.model.scope('_page.room');
}
}
UUIDs
Models provide a method to create globally unique ids. These can be used as part of a path or within mutator methods.
uuid = model.id()
uuid
Returns a globally unique identifier that can be used for model operations