Model API
Built in functionality
Instance-level methods
These methods are called on concrete instances of a model:
inst.values()
: Returns the model data as a plain JS object. This preserves any ImmutableJS values you may have set inside a model.inst.toJS()
: Deeply coverts the model data to plain JS objects. This does not preserve any ImmutableJS values you may have set.inst.unsetId()
: Unsets theidField
of the model instance
Class-level methods
These methods are called on the classes themselves, not on instances:
Model.blank()
: returns a new instance of the model with default values specified infields
Model.fieldNames()
: returns all field names as an arrayModel.submodelFieldDNames()
: A class-level method which returns all field names of nested classesModel.item()
: returns a newProvider
asserting that the API response returns a single modelModel.list()
: Returns a newProvider
asserting that the API response returns a list of modelsModel.getItem(params<Object>)
: returns a newQuery
requsting a single item to be loadedModel.getList(params<Object>)
: returns a newQuery
requsting a list of items to be loaded
Defining props
Models are a core part of tectonic, and define all of the attributes for your resources.
In order to define a model you must extend Tectonic’s base class. There are three main class variables you need to define:
import { Model } from 'tectonic';
class UserModel extends Model {
// 'modelName' is a required field and must be unique among all models
static modelName = 'user';
// 'idField' is the attribute which holds the model ID; this defaults to 'id'
// if left undefined. This must be set if the ID is in another field.
static idField = 'id';
// 'fields' define the attributes that this model can hold, along with
// any default values for a new, empty model. These default vaues are
// also passed to a component when data is pending.
static fields = {
id: undefined,
name: 'Anonymoose',
email: '',
}
}
Models can be nested:
class PostModel extends Model {
static modelName = 'post';
static fields = {
id: undefined,
slug: '',
body: '',
// ensure the 'author' object is converted into a UserModel
author: new UserModel(),
}
}
Data manipulation
Often you’ll need to manipulate a model’s data to show correctly within a component. You can define custom methods on your class to manipulate data so that you keep your components decoupled from data logic:
class User extends Model {
static modelName = 'user';
static fields = {
id: undefined,
email: '',
avatar: '',
}
getAvatar() {
if (this.avatar === '') {
return 'https://placehold.it/500x500';
}
return this.avatar
}
}
Now we can use this.props.user.getAvatar()
to show a placeholder or their
avatar.
Filtering data
Models can also define a filter function. All data passed to a model during construction will be filtered via this function before being set:
class User extends Model {
// this needs to be a static function so that it's set on the class
// as a prototypical method, not the instance.
static filter(data) {
// The data returned from this function will be used to set the model's
// fields.
return {
...data,
fullName: `${data.firstName} ${data.lastName}`,
};
}
}
Note that often using instance methods as explained above in the data
manipulation
section is often a better idea.
Gotchas
Models can’t have a size
attribute due to conflicting field names with
ImmutableJS. If you have a size
attribute from your API you should rename
this within your frontend model and use filtering to rename the field before
data is set.
We know this kinda sucks. Sorry.