StructureJS
0.15.2A class based utility library for building modular and scalable web platform applications. Features opt-in classes and utilities which provide a solid foundation and toolset to build your next project.
- import IBaseModel from '../interface/IBaseModel';
- import IBaseModelOptions from '../interface/IBaseModelOptions';
- import BaseObject from '../BaseObject';
- import Util from '../util/Util';
- /**
- * Base Model is a design pattern used to transfer data between software application subsystems.
- *
- * Note: If the data doesn't match the property names you can set the value manually after update super method has been called.
- * Also in the class you inherit BaseModel from you can override the update method to handle the data how you want.
- *
- * @class BaseModel
- * @extends BaseObject
- * @param [data] {any} Provide a way to update the base model upon initialization.
- * @param [opts] {{ expand:boolean }} Options for the base model.
- * @module StructureJS
- * @submodule model
- * @requires Extend
- * @requires BaseObject
- * @requires Util
- * @constructor
- * @author Robert S. (www.codeBelt.com)
- * @example
- * // Example how to extend the BaseModel class.
- * let data = {
- * make: 'Tesla',
- * model: 'Model S',
- * YeAr: 2014,
- * feature: {
- * abs: true,
- * airbags: true
- * }
- * }
- * let carModel = new CarModel(data);
- *
- *
- * // Example how to extend the BaseModel class.
- * class CarModel extends BaseModel {
- *
- * // You need to have properties so the data will get assigned.
- * // If not the data will not get assigned to the model.
- * make = null;
- * model = null;
- * year = null;
- * allWheel = false; // Set a default value
- *
- * // You can assign BaseModel to a property which will
- * // automatically created it and pass the data to it.
- * feature = FeatureModel
- *
- * // If you have an array of data and want them assign to a BaseModel.
- * feature = [FeatureModel];
- *
- * constructor(data = {}, opts = {}) {
- * super(opts);
- *
- * if (data) {
- * this.update(data);
- * }
- * }
- *
- * // @overridden BaseModel.update
- * update(data) {
- * super.update(data);
- *
- * // If the data doesn't match the property name.
- * // You can set the value(s) manually after the update super method has been called.
- * this.year = data.YeAr;
- * }
- * }
- */
- class BaseModel extends BaseObject implements IBaseModel
- {
- /**
- * This property helps distinguish a BaseModel from other functions.
- *
- * @property IS_BASE_MODEL
- * @type {boolean}
- * @public
- * @static
- * @readonly
- */
- public static readonly IS_BASE_MODEL:boolean = true;
- /**
- * @property sjsOptions
- * @type {IBaseModelOptions}}
- * @public
- */
- protected sjsOptions:IBaseModelOptions = {
- expand: false,
- };
- constructor(opts:IBaseModelOptions = {})
- {
- super();
- this.sjsOptions.expand = opts.expand === true;
- }
- /**
- * Provide a way to update the Base Model.
- *
- * @method update
- * @param [data={}] {any}
- * @public
- * @example
- * // Example of updating some of the data:
- * carModel.update({ year: 2015, allWheel: true});
- *
- * // Of course you can also do it the following way:
- * carModel.year = 2015;
- * carModel.allWheel = false;
- */
- public update(data:any = {}):any
- {
- Object
- .keys(this)
- .forEach(propertyName =>
- {
- // Ignore the sjsId property because it is set in the BaseObject constructor and we don't want to update it.
- if (propertyName !== 'sjsId')
- {
- const propertyData = this[propertyName];
- const updateData = data[propertyName];
- const dataToUse = (updateData !== void 0) ? updateData : propertyData;
- this._updatePropertyWithDataPassedIn(propertyName, dataToUse);
- }
- });
- return this;
- }
- /**
- * Adds the updateData to the property
- *
- * @method _updatePropertyWithDataPassedIn
- * @param propertyName
- * @param updateData
- * @protected
- */
- protected _updatePropertyWithDataPassedIn(propertyName:any, updateData:any):void
- {
- // If the current property on the model is an array and the updateData is an array.
- if ((this[propertyName] instanceof Array === true) && (updateData instanceof Array === true))
- {
- const isPropertyDataValueAnUninstantiatedBaseModel = (typeof this[propertyName][0] === 'function' && this[propertyName][0].IS_BASE_MODEL === true);
- const isUpdateDataValueAnUninstantiatedBaseModel = (typeof updateData[0] === 'function' && updateData[0].IS_BASE_MODEL === true);
- if (isPropertyDataValueAnUninstantiatedBaseModel === false)
- {
- this[propertyName] = updateData.map(data => this._updateData(null, data));
- }
- else if (isPropertyDataValueAnUninstantiatedBaseModel === true && isUpdateDataValueAnUninstantiatedBaseModel === false)
- {
- // If the property data is an uninstantiated BaseModel then we assume the update data passed in
- // needs to be create as that BaseModel Class.
- const baseModel = this[propertyName][0];
- this[propertyName] = updateData.map(data => this._updateData(baseModel, data));
- }
- else
- {
- this[propertyName] = [];
- }
- }
- else
- {
- this[propertyName] = this._updateData(this[propertyName], updateData);
- }
- }
- /**
- * @method _updateData
- * @param propertyData
- * @param updateData
- * @protected
- */
- protected _updateData(propertyData:any, updateData:any):any
- {
- let returnData:any = null;
- if (this.sjsOptions.expand === false && typeof updateData === 'function' && updateData.IS_BASE_MODEL === true)
- {
- // If updateData is a function and has an IS_BASE_MODEL static property then it must be a child model and we need to return null
- // so it cleans up the BaseModel functions on the property.
- // To create empty model(s) pass { expand: true } for the options.
- return null;
- }
- if (typeof propertyData === 'function' && propertyData.IS_BASE_MODEL === true && updateData)
- {
- // If the propertyData is an instance of a BaseModel class and has not been created yet.
- // Instantiate it and pass in the updateData to the constructor.
- returnData = new propertyData(updateData, this.sjsOptions);
- }
- else if ((propertyData instanceof BaseModel) === true)
- {
- // If propertyData is an instance of a BaseModel class and has already been created.
- // Call the update method and pass in the updateData.
- returnData = propertyData.update(updateData);
- }
- else if ((updateData instanceof BaseModel) === true)
- {
- returnData = updateData.clone();
- }
- else
- {
- // Else just return the updateData to the property.
- returnData = updateData;
- }
- return returnData;
- }
- /**
- * Converts the Base Model data into a JSON object and deletes the sjsId property.
- *
- * @method toJSON
- * @returns {any}
- * @public
- * @example
- * const obj = carModel.toJSON();
- */
- public toJSON():any
- {
- const clone:any = Util.clone(this);
- return Util.deletePropertyFromObject(clone, ['sjsId', 'sjsOptions']);
- }
- /**
- * Converts a Base Model to a JSON string,
- *
- * @method toJSONString
- * @returns {string}
- * @public
- * @example
- * const str = carModel.toJSONString();
- */
- public toJSONString():string
- {
- return JSON.stringify(this.toJSON());
- }
- /**
- * Converts the string json data into an Object and calls the {{#crossLink "BaseModel/update:method"}}{{/crossLink}} method with the converted Object.
- *
- * @method fromJSON
- * @param json {string}
- * @public
- * @example
- * const str = '{"make":"Tesla","model":"Model S","year":2014}'
- * const carModel = new CarModel();
- * carModel.fromJSON(str);
- */
- public fromJSON(json:string):any
- {
- const parsedData:any = JSON.parse(json);
- this.update(parsedData);
- return this;
- }
- /**
- * Create a clone/copy of the Base Model.
- *
- * @method clone
- * @returns {BaseModel}
- * @public
- * @example
- * const clone = carModel.clone();
- */
- public clone():BaseModel
- {
- const clonedBaseModel:BaseModel = new (<any>this).constructor(this);
- return clonedBaseModel;
- }
- }
- export default BaseModel;