Last active
December 20, 2015 01:19
-
-
Save FireNeslo/6048662 to your computer and use it in GitHub Desktop.
An object with map and array like methods that keeps references to the same object for as long as possible;
if you attatch a promise it will also resolve that promise before attempting to run any other chained functions.
Useful for keeping references in for example angularjs while executing async logic.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function addScript(src) { | |
var script = document.createElement("script"); | |
script.src = src; | |
document.body.appendChild(script); | |
return addScript; | |
} | |
addScript('//rawgithub.com/kriskowal/q/master/q.min.js'); | |
/** | |
* A Object wrapper with some iteration helpers. | |
* @constructor | |
* @param {object} [obj] - The object to extend. | |
* @param {promise} [condition] - promise that needs to be fullfilled before running iteration. | |
*/ | |
function ObjMap (obj, condition) { | |
var _self = this; | |
obj = obj || {}; | |
if(condition && ObjMap.isFunction(condition.then) ) { | |
this.condition(condition); | |
} | |
this.extend(obj); | |
} | |
ObjMap.isObject = function(obj) { | |
return obj === Object(obj); | |
}; | |
ObjMap.isFunction = function(obj) { | |
return typeof obj === 'function'; | |
}; | |
ObjMap.isFinite = function(obj) { | |
return isFinite(obj) && !isNaN(parseFloat(obj)); | |
}; | |
ObjMap.isNaN = function(obj) { | |
return _.isNumber(obj) && obj != +obj; | |
}; | |
ObjMap.isBoolean = function(obj) { | |
return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; | |
}; | |
ObjMap.isNull = function(obj) { | |
return obj === null; | |
}; | |
ObjMap.isUndefined = function(obj) { | |
return obj === void 0; | |
}; | |
/** | |
* Add a conditon for iteration to continue | |
* @function | |
* @param {promise} promise - A condiion to be met before continuing iteration | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.condition = function(promise) { | |
var _self = this; | |
if(this.$$condition) { | |
this.$$condition = this.$$condition.then(function() { | |
_self.$$condition = promise; | |
return promise.then(function() { | |
delete _self.$$condition; | |
}) | |
}) | |
} else { | |
this.$$condition = promise.then(function() { | |
delete _self.$$condition; | |
}) | |
} | |
return this; | |
}; | |
/** | |
* Iterate Object as if it vas an array value key | |
* @function | |
* @param {function} cb- Iteration function with, value, key as params. | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.forEach = function(cb){ | |
var _self = this; | |
if(this.$$condition) { | |
this.$$condition.then(function() { | |
for(var a in _self) { | |
if(_self.hasOwnProperty(a) && a[0] != '$' ) { | |
cb(_self[a], a); | |
} | |
} | |
}) | |
} else { | |
for(var a in this) { | |
if(this.hasOwnProperty(a) && a[0] != '$') { | |
cb(this[a], a); | |
} | |
} | |
} | |
return this; | |
}; | |
/** | |
* Get the object keys as an array | |
* @function | |
* @returns {array} keys - list of object keys | |
*/ | |
ObjMap.prototype.keys = function() { | |
var arr = []; | |
this.forEach(function(val, key) { | |
arr.push(key); | |
}) | |
return arr; | |
}; | |
/** | |
* Create a list of object values | |
* @function | |
* @returns {array} values - a list of values | |
*/ | |
ObjMap.prototype.values = function() { | |
return this.toArray(); | |
}; | |
/** | |
* Add properties to object | |
* @function | |
* @param {object} obj - object with new properties.. | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.extend = function(obj){ | |
var _self = this; | |
this.forEach.call(obj, function(val,key) { | |
_self[key] = val; | |
}); | |
return this; | |
}; | |
/** | |
* Remove properties from object | |
* @function | |
* @param {object} cb- object with props to be removed; | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.exclude = function(obj){ | |
var _self = this; | |
this.forEach.call(obj, function(val,key) { | |
delete _self[key]; | |
}); | |
return this; | |
}; | |
/** | |
* Iterate Object as if it vas an array value key | |
* @function | |
* @param {string} key - New proberty key | |
* @param value - New property value | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.add = function(key, obj){ | |
this[key] = obj; | |
return this; | |
}; | |
/** | |
* Add all values from array with object property as key | |
* @function | |
* @param {array} array - New property values | |
* @param {string} key - Proberty key of array values to use as key. | |
* @param {boolean} remove - Remove the key from object | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.addAll = function( array, key, remove){ | |
var _self = this; | |
array.forEach(function(val) { | |
_self.add(val[key], val); | |
if(remove) { | |
delete val[key]; | |
} | |
}); | |
return this; | |
}; | |
/** | |
* Remove property by key | |
* @function | |
* @param {string} key - Key of proberty to remove. | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.remove = function(key){ | |
delete this[key]; | |
return this; | |
}; | |
/** | |
* Remove properties from array | |
* @function | |
* @param {array} keys - Keys of proberties to remove. | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.removeAll = function(array){ | |
var _self = this; | |
array.forEach(function(val, key) { | |
_self.remove(key); | |
}); | |
return this; | |
}; | |
/** | |
* Remove all properties | |
* @function | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.clear = function() { | |
var _self = this; | |
this.forEach(function(val, key) {_self.remove(key);}); | |
return this; | |
}; | |
/** | |
* Get number of properties | |
* @function | |
* @returns {number} size - Nuber of properties | |
*/ | |
ObjMap.prototype.size = function() { | |
var _self = this; | |
var size = 0; | |
this.forEach(function() {size += 1;}); | |
return size; | |
}; | |
/** | |
* Iterate and replace values | |
* @function | |
* @param {function} cb - Iteration function | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.map = function(cb){ | |
var _self = this; | |
this.forEach(function(val, key) { | |
_self[key] = cb(val, key); | |
}); | |
return this; | |
} | |
/** | |
* Get value by key or default if none | |
* @function | |
* @param {string} key - Key to get | |
* @param defaulr - default value | |
* @returns value - value of key or default | |
*/ | |
ObjMap.prototype.get = function(key, _default){ | |
return this[key] || _default; | |
} | |
/** | |
* Set property | |
* @function | |
* @param {string} key - Key to get | |
* @param value - value to set | |
* @returns {ObjMap} self - a reference to itself for chaining | |
*/ | |
ObjMap.prototype.set = function(key, val){ | |
this[key] = val; | |
return this; | |
} | |
/** | |
* Create array from object | |
* @function | |
* @param {string} [id] - if specified assigns the property key as value of id; | |
* @param {array} array - array referece to use for result. | |
* @returns {array} self - The map as an array | |
*/ | |
ObjMap.prototype.toArray = function(id, array){ | |
var arr = array || []; | |
var _self = this; | |
this.forEach(function(val, key) { | |
if(id) { | |
val = _self.clone(val); | |
val[id] = key; | |
} | |
arr.push(val); | |
}); | |
return arr; | |
} | |
/** | |
* Create a normal object from ObjMap | |
* @function | |
* @returns {object} self - The map as a normal object | |
*/ | |
ObjMap.prototype.toJSON = function(){ | |
var json = {}; | |
this.forEach(function(val, key) { | |
json[key] = val; | |
}); | |
return json; | |
} | |
/** | |
* Create a clone from an object or self | |
* @function | |
* @param {object} [obj] - if specified is cloned | |
* @returns {object} clone - TThe cloned object | |
*/ | |
ObjMap.prototype.clone = function clone(obj) { | |
if (null == obj || "object" != typeof obj) { | |
obj = this; | |
}; | |
var copy = obj.constructor(); | |
for (var attr in obj) { | |
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; | |
} | |
return copy; | |
} | |
/** | |
* An error for next() iteration ower async object | |
* @constructor | |
* @param {Promise} promise - the condition that still needs to be fullfilled | |
*/ | |
ObjMap.AsyncIterationError = function AsyncItretaionError(promise) { | |
this.name = "ReferenceError"; | |
this.message = 'Iterate async error'; | |
this.condition = promise; | |
}; | |
ObjMap.AsyncIterationError.prototype.toString = function() { | |
return this.name + ": " + this.message; | |
}; | |
/** | |
* Next key | |
* @function | |
* @returns {string} key - Next key in object | |
*/ | |
ObjMap.prototype.next = function(){ | |
if(!this.$current) { | |
this.$current = { | |
array : this.keys(), | |
index : 0 | |
} | |
} | |
if(this.$$condition) { | |
throw new ObjMap.AsyncIterationError(this.$$condition); | |
} else { | |
if (this.hasNext()) { | |
return this.$current.array[this.$current.index++]; | |
} else { | |
delete this.$current; | |
return undefined; | |
} | |
} | |
}; | |
/** | |
* Has next key | |
* @function | |
* @returns {boolean} hasNext - If has next key | |
*/ | |
ObjMap.prototype.hasNext = function() { | |
return this.$current ? (this.$current.index < this.$current.array.length) : !!this.size(); | |
} | |
// example | |
function example() { | |
function delay(ms) { | |
var deferred = Q.defer(); | |
setTimeout(deferred.resolve, ms); | |
return deferred.promise; | |
} | |
var m = new ObjMap(); | |
var promise = delay(1000).then(function() { | |
console.log("delay"); | |
m.extend({"arrived":"late"}); | |
}); | |
var keys = m. | |
condition(promise). | |
keys(); | |
console.log("now", keys) | |
setTimeout(function() { | |
console.log("later", keys) | |
}, 1100); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment