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 the- idFieldof 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 in- fields
- Model.fieldNames(): returns all field names as an array
- Model.submodelFieldDNames(): A class-level method which returns all field names of nested classes
- Model.item(): returns a new- Providerasserting that the API response returns a single model
- Model.list(): Returns a new- Providerasserting that the API response returns a list of models
- Model.getItem(params<Object>): returns a new- Queryrequsting a single item to be loaded
- Model.getList(params<Object>): returns a new- Queryrequsting 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.