import { isArray, isFunction, addObservablesTo, addComputablesTo } from 'Common/Utils'; function dispose(disposable) { if (disposable && isFunction(disposable.dispose)) { disposable.dispose(); } } function typeCast(curValue, newValue) { switch (typeof curValue) { case 'boolean': return 0 != newValue && !!newValue; case 'number': return isFinite(newValue) ? parseFloat(newValue) : 0; case 'string': return null != newValue ? '' + newValue : ''; case 'object': if (curValue.constructor.reviveFromJson) { return curValue.constructor.reviveFromJson(newValue); } if (isArray(curValue) && !isArray(newValue)) return []; } return newValue; } export class AbstractModel { constructor() { /* if (new.target === AbstractModel) { throw new Error("Can't instantiate AbstractModel!"); } */ this.subscribables = []; } addObservables(observables) { addObservablesTo(this, observables); } addComputables(computables) { addComputablesTo(this, computables); } addSubscribables(subscribables) { Object.entries(subscribables).forEach(([key, fn]) => this.subscribables.push( this[key].subscribe(fn) ) ); } /** Called by delegateRunOnDestroy */ onDestroy() { /** dispose ko subscribables */ this.subscribables.forEach(dispose); /** clear object entries */ // Object.entries(this).forEach(([key, value]) => { Object.values(this).forEach(value => { /** clear CollectionModel */ let arr = ko.isObservableArray(value) ? value() : value; arr && arr.onDestroy && value.onDestroy(); /** destroy ko.observable/ko.computed? */ dispose(value); /** clear object value */ // this[key] = null; // TODO: issue with Contacts view }); // this.subscribables = []; } /** * @static * @param {FetchJson} json * @returns {boolean} */ static validJson(json) { return !!(json && ('Object/'+this.name.replace('Model', '') === json['@Object'])); } /** * @static * @param {FetchJson} json * @returns {*Model} */ static reviveFromJson(json) { let obj = this.validJson(json) ? new this() : null; obj && obj.revivePropertiesFromJson(json); return obj; } revivePropertiesFromJson(json) { let model = this.constructor; try { if (!model.validJson(json)) { return false; } Object.entries(json).forEach(([key, value]) => { if ('@' !== key[0]) { key = key[0].toLowerCase() + key.substr(1); switch (typeof this[key]) { case 'function': if (ko.isObservable(this[key])) { this[key](typeCast(this[key](), value)); // console.log('Observable ' + (typeof this[key]()) + ' ' + (model.name) + '.' + key + ' revived'); } // else console.log(model.name + '.' + key + ' is a function'); break; case 'boolean': case 'number': case 'object': case 'string': this[key] = typeCast(this[key], value); break; // fall through case 'undefined': default: // console.log((typeof this[key])+' '+(model.name)+'.'+key+' not revived'); } } }); } catch (e) { console.log(model.name); console.error(e); } return true; } }