Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * A model base class that extends Backbone.Model to provide both
- * common functionality and common model properties.
- *
- * Common properties are defined by property configuration data objects returned
- * by the propConfig getter.
- *
- * Common functionality determined by propConfig includes:
- * - defaults
- * - server data parsing
- */
- class ABaseModel extends Backbone.Model {
- /**
- * Returns an array of objects that are used to generate properties and
- * default values for the model class. Subclasses that override this should
- * concat additional prop objects to the results of super, e.g.:
- * return super.propConfig.concat([{...}]);
- * so that properties defined in ABaseModel or other parent classes aren't lost.
- *
- * Each prop object can have the following values:
- * - prop {string}: the name of the property to be defined.
- * Required.
- * - attr {string}: the name of the Backbone model attribute. Useful if
- * the server returns an attribute like `_xzserver_full_name` that would
- * read better in the frontend as `fullName`.
- * Defaults to `prop` value.
- * - get {func}: the getter function.
- * Defaults to `Backbone.Model.get(attr)`.
- * - set {func}: the setter function. If this is present but undefined,
- * no setter will be created for the property, resulting in a read-only prop.
- * Defaults to `Backbone.Model.set(attr, value)`
- * - configurable {bool}: `true` if and only if the type of this property
- * descriptor may be changed and if the property may be deleted from
- * the corresponding object.
- * Defaults to `false`.
- * - enumerable {bool}: `true` if and only if this property shows up during
- * enumeration of the properties on the corresponding object.
- * Defaults to `true`.
- *
- * - default {* | func}: default value for the property, as returned by
- * Backbone.Model.defaults. If a function, called with `this` set to
- * the model instance. A function should be used to return all
- * object defaults (i.e. non-primitives), e.g.:
- * {prop: 'data', default: function() {return {};}}
- * since otherwise all model instances would share the same single object.
- *
- * - mapping {string}: if set, `parse` will map server values to frontend values.
- * Options:
- * 'date': passes the value (which should be a string in a format
- * recognized by the `Date.parse()`` method) to a new `Date` constructor,
- * and stores the date object in the model instance.
- * 'relation': passes the value (which should be an object or an array
- * of objects with model attributes) to a model constructor,
- * as specified by the `class` property, and stores the new
- * model instance or a model collection in the owning model instance.
- * Uses a new Backbone.Collection if the server value is an array.
- * - class {class}: the class to construct for relation mappings.
- * Required if mapping == 'relation'.
- *
- * Examples:
- *
- * // Simple prop
- * {prop: 'name'}
- *
- * // Prop with different server attribute name
- * {prop: 'firstName', attr: 'first_name'}
- *
- * // Un-modifiable prop
- * {prop: 'emailConfirmed', set: undefined}
- *
- * // Un-enumerable prop
- * {prop: 'syncId', enumerable: false}
- *
- * // Primitive default value
- * {prop: 'active', default: true}
- *
- * // Object default value
- * {prop: 'extraData', default: function() { return {}; }}
- *
- * // Date default value
- * {prop: 'created', default: function() { return new Date(); }}
- *
- * // Uses date parsing
- * {prop: 'lastModified', mapping: 'date'}
- *
- * // Uses relationship parsing
- * {prop: 'address', mapping: 'relation', class: AAddress}
- *
- * @returns {array}
- */
- static get propConfig() {
- return [];
- }
- /**
- * Configures properties on the model class based on the results of propConfig.
- * Should be called on each subclass of ABaseModel.
- */
- static configureProps() {
- for (const propData of this.propConfig) {
- const prop = propData.prop;
- // attr is optional, defaults to prop
- const attr = propData.attr || propData.prop;
- const descriptor = propData;
- Object.defineProperty(this.prototype, prop, Object.assign({
- get: function() {
- return this.get(attr);
- },
- set: function(value) {
- this.set(attr, value);
- },
- enumerable: true,
- }, descriptor));
- }
- }
- /**
- * `Backbone.Model.defaults` override gets defaults from propConfig.
- * Called automatically by Backbone.Model.constructor.
- */
- get defaults() {
- const defaults = {};
- this.constructor.propConfig.forEach((propData) => {
- const attr = propData.attr || propData.prop;
- let def = propData.default;
- if ('function' === typeof def)
- {
- def = propData.default.call(this)
- }
- defaults[attr] = def;
- })
- return defaults;
- }
- /**
- * Returns `propConfig` array, filtered by properties that have a `mapping` value.
- * @returns {array}
- */
- get mappings() {
- return this.constructor.propConfig.filter((propData) => {
- return !!propData.mapping;
- });
- }
- /**
- * Override `Backbone.Model.parse` to map API values to model values based on
- * propConfig. `parse` is called automatically whenever a model's data is
- * returned by the server, in `fetch`, and `save`.
- */
- parse(response) {
- for (const propData of this.mappings) {
- const attr = propData.attr || propData.prop;
- const mapping = propData.mapping;
- const val = response[attr];
- if (null !== val && undefined !== val) {
- switch (mapping) {
- case 'date':
- response[attr] = new Date(val);
- break;
- case 'relation':
- if (val instanceof Array)
- {
- const collection = new Backbone.Collection();
- collection.model = propData.class;
- collection.add(val, {parse: true});
- response[attr] = collection;
- }
- else
- {
- response[attr] = new propData.class(val, {parse: true});
- }
- break;
- default:
- throw new Error(`Unknown mapping type ${mapping} for prop ${attr}`);
- }
- }
- }
- return response;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement