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 theidFieldof 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 infieldsModel.fieldNames(): returns all field names as an arrayModel.submodelFieldDNames(): A class-level method which returns all field names of nested classesModel.item(): returns a newProviderasserting that the API response returns a single modelModel.list(): Returns a newProviderasserting that the API response returns a list of modelsModel.getItem(params<Object>): returns a newQueryrequsting a single item to be loadedModel.getList(params<Object>): returns a newQueryrequsting 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.