I'm trying to extend js native array inside angular service to add some extra features without prototyping global objects.
app.factory('Collection', function($http, $q) {
var Collection = function(arr) {
this.key = 'id';
this._last = 0;
this._first = 77777777; //just big number.
this.append(arr);
}
Collection.prototype = new Array;
Collection.prototype.orderBy = function(n, reverse) {
if (reverse) {
this.sort(function(a, b) {
return b[n] - a[n];
})
} else {
this.sort(function(a, b) {
return a[n] - b[n];
})
}
}
Collection.prototype.spliceBy = function(key, val) {
for (var i = 0; i < this.length; i++) {
if (this[i][key] !== val) {
this.splice(i, 1); ///THIS NEVER HAPPENS !!
console.log('removed ' + i + ' from ', this);
}
}
}
Collection.prototype.subset = function(key, val) {
return this.filter(function(v) {
return (v[key] === val);
});
}
Collection.prototype.add = function(obj) {
for (var i = 0; i < this.length; i++) {
if (this[i][this.key] > this._last) {
this._last = this[i][this.key];
}
if (this[i][this.key] < this._first) {
this._first = this[i][this.key];
}
if (this[i][this.key] === data[this.key]) {
if (override) {
this[i] = data;
console.log('updated uniquePush');
}
return i;
break;
}
}
var id = this.push(data) - 1;
data._index = id;
return id;
}
return collection
});
This is working fine except for the spliceBy function.
I need to filter out elements that does not have value = x;
For example in my controller
.controller(function($scope,Collection){
$scope.posts = new Collection;
$scope.posts.add({id:1,type:'post'});
$scope.posts.add({id:2,type:'comment'});
//Collection is now [{id:1,type:post},{id:2,type:comment}];
//i want to remove all comments from array
$scope.posts.spliceBy('type','comment');
});
Yet nothing happens when calling spliceBy :*(
The spliceBy function will not work if you have two elements to remove in a row, because splice is updating the indexes from i to array.length. Try this instead:
Collection.prototype.spliceBy = function(key, val) {
var i = this.length;
while (i--) {
if (this[i][key] !== val) {
this.splice(i, 1); ///THIS NEVER HAPPENS !!
console.log('removed ' + i + ' from ', this);
}
}
}
Related
I was making a HashTable to have as an example and have it saved for any problem, but I ran into a problem trying to implement a method that returns true or false in case the value belongs to the HashTable, since it is inside a arrays of objects as comment in the code.
I have tried for loops, .map and for of, but it always fails, if someone could help me.
function HashTable () {
this.buckets = [];
this.numbuckets = 35;
}
HashTable.prototype.hash = function (key) {
let suma = 0;
for (let i = 0; i < key.length; i++) {
suma = suma + key.charCodeAt(i);
}
return suma % this.numbuckets;
}
HashTable.prototype.set = function (key, value) {
if (typeof key !== "string") {
throw new TypeError ("Keys must be strings")
} else {
var index = this.hash(key);
if(this.buckets[index] === undefined) {
this.buckets[index] = {};
}
this.buckets[index][key] = value;
}
}
HashTable.prototype.get = function (key) {
var index = this.hash(key);
return this.buckets[index][key];
}
HashTable.prototype.hasKey = function (key) {
var index = this.hash(key);
return this.buckets[index].hasOwnProperty(key)
}
HashTable.prototype.remove = function (key) {
var index = this.hash(key);
if (this.buckets[index].hasOwnProperty(key)) {
delete this.buckets[index]
return true;
}
return false;
}
HashTable.prototype.hasValue = function (value) {
let result = this.buckets;
result = result.flat(Infinity);
return result // [{Name: Toni}, {Mame: Tino}, {Answer: Jhon}]
}
You can use Object.values() to get the values of all the propertyies in the bucket.
function HashTable() {
this.buckets = [];
this.numbuckets = 35;
}
HashTable.prototype.hash = function(key) {
let suma = 0;
for (let i = 0; i < key.length; i++) {
suma = suma + key.charCodeAt(i);
}
return suma % this.numbuckets;
}
HashTable.prototype.set = function(key, value) {
if (typeof key !== "string") {
throw new TypeError("Keys must be strings")
} else {
var index = this.hash(key);
if (this.buckets[index] === undefined) {
this.buckets[index] = {};
}
this.buckets[index][key] = value;
}
}
HashTable.prototype.get = function(key) {
var index = this.hash(key);
return this.buckets[index][key];
}
HashTable.prototype.hasKey = function(key) {
var index = this.hash(key);
return this.buckets[index].hasOwnProperty(key)
}
HashTable.prototype.remove = function(key) {
var index = this.hash(key);
if (this.buckets[index].hasOwnProperty(key)) {
delete this.buckets[index]
return true;
}
return false;
}
HashTable.prototype.hasValue = function(value) {
return this.buckets.some(bucket => Object.values(bucket).includes(value));
}
let h = new HashTable;
h.set("Abc", 1);
h.set("Def", 2);
console.log(h.hasValue(1));
console.log(h.hasValue(3));
I am trying to convert the XML to JSON.Here am facing challenge my xml have #attributes name as "value" in all tag. while convert into xml to JSON i am using the below code.
var xml = "<Message><id value="123"></id><type value="Test"></type></Message>"
var json = XMLtoJSON(xml, ["type", "space", "xmlns", "html"]);
var result = JSON.stringify(json)
function XMLtoJSON(xml, ignored) {
var r, children = xml.*, attributes = xml.#*, length = children.length();
if(length == 0) {
r = xml.toString();
} else if(length == 1) {
var text = xml.text().toString();
if(text) {
r = text;
}
}
if(r == undefined) {
r = {};
for each (var child in children) {
var name = child.localName();
var json = XMLtoJSON(child, ignored);
var value = r[name];
if(value) {
if(value.length) {
value.push(json);
} else {
r[name] = [value, json]
}
} else {
r[name] = json;
}
}
}
if(attributes.length()) {
var a = {}, c = 0;
for each (var attribute in attributes) {
var name = attribute.localName();
if(ignored && ignored.indexOf(name) == -1) {
a["_" + name] = attribute.toString();
c ++;
}
}
if(c) {
if(r) a._ = r;
return a;
}
}
return r;
}
Input XML :
<Message><id value="123"></id><type value="Test"></type></Message>
Actual Output:
{"id":{"_value":"123"},"type":{"_value":"Test"}}
Expected Output:
{"id":"123","type":"Test"}
Guide me where am missing the part to get the expected output.
Regards,
nkn1189
do you think if you do this way will work for you?
put your actual output from that parser to this function:
function convertToExpectedOutput(obj){
var result = {}
for (var i in obj){
if (i == "_value")
return obj[i];
else
result[i] = convertToExpectedOutput(obj[i])
}
return result;
}
convertToExpectedOutput(actualOutput)
So, for your array, hange the convertToExpectedOutput to this way and it will give the expected result:
function convertToExpectedOutput(obj){
var result = {}
for (var i in obj){
if (i == "_value")
return obj[i];
else
if (Array.isArray(obj[i])){
result[i] = [];
arr = obj[i]
for (var j in arr)
result[i].push(convertToExpectedOutput(arr[j]))
}
else
result[i] = convertToExpectedOutput(obj[i])
}
return result;
}
My application calls the module to parse nested JSON object, to read values of 2 keys.
parseData(str, function (error, str) {
if (err) {
console.log("Error - parseData : ", err);
} else {
console.log(str);
}
And the parseData module is as follows
function parseData(str, callback) {
function recursiveFunction(obj) {
var keysArray = Object.keys(obj);
for (var i = 0; i < keysArray.length; i++) {
var key = keysArray[i];
var value = obj[key];
if (value === Object(value)) {
parseData(value);
} else {
if (key == 'title') {
title = value;
}
if (key == 'extract') {
var extract = value.replace(/(\r\n|\n|\r)/gm," ");
callback(null, JSON.stringify('{"title":'+ title + ', "text":' + extract));
}
}
}
}
recursiveFunction(str);
}
But it shows following error
/modules/parseData.js:22
callback(null, JSON.stringify('{"title":'+ title + ', "text":' + extract));
^
TypeError: callback is not a function
Why is callback failing ? How to return back JSON object ?
EDIT
There were some errors in the code and now corrected.
function parseData(str, callback) {
function recursiveFunction(obj) {
var keysArray = Object.keys(obj);
for (var i = 0; i < keysArray.length; i++) {
var key = keysArray[i];
var value = obj[key];
if (value === Object(value)) {
recursiveFunction(value);
} else {
if (key == 'title') {
title = value;
}
if (key == 'extract') {
var extract = value.replace(/(\r\n|\n|\r)/gm," ");
callback(null, JSON.stringify('{"title":'+ title + ', "text":' + extract));
}
}
}
}
recursiveFunction(str);
};
You're calling parseData(value); and not passing a callback; pass callback if you want that original callback to be used.
I am formatting an array in the function inputCategories, and am unable to correctly add a third argument of "category" - forcing me replicate the function multiple times.
Here is the current state:
Calling the function with arguments.
$scope.categories = inputCategories($scope.item.categories, $scope.settings.categories);
function inputCategories (input, settings) {
var updatedSettings = [];
angular.forEach(input, function(obj) {
updatedSettings.push({"category": obj, "ticked": true});
});
var list = updatedSettings.concat(settings);
list.sort(function(a, b) {
return (a.category > b.category) - (a.category < b.category);
});
for ( var i = 1; i < list.length; i++ ){
if(list[i-1].category == list[i].category) {
list.splice(i,1);
}
}
return list;
};
Here are the places which would require a third argument of "category".
function inputCategories (input, settings) {
var updatedSettings = [];
angular.forEach(input, function(obj) {
updatedSettings.push({****"category"****: obj, "ticked": true});
});
var list = updatedSettings.concat(settings);
list.sort(function(a, b) {
return (a.****category**** > b.****category****) - (a.****category**** < b.****category****);
});
for ( var i = 1; i < list.length; i++ ){
if(list[i-1].****category**** == list[i].****category****) {
list.splice(i,1);
}
}
return list;
};
I think that the issue I am having is because I am mixing up strings and a variable that is a string, inside of the object on the fourth line...?
Perhaps you could do something like this:
function inputCategories (input, settings, category) {
var updatedSettings = [];
angular.forEach(input, function(obj) {
var setting = { "ticked": true };
setting[category] = obj;
updatedSettings.push(setting);
});
var list = updatedSettings.concat(settings);
list.sort(function(a, b) {
return (a[category] > b[category]) - (a[category] < b[category]);
});
for ( var i = 1; i < list.length; i++ ){
if(list[i-1][category] == list[i][category]) {
list.splice(i,1);
}
}
return list;
};
I am working with javascript. I would like to inherit Common object with other objects in javascript. Is it possible to do it? I mean to convert this js to a prototype model.
function setEvent(evt, ele, callback) {
var ele = getEle(ele);
if (ele.length === undefined) {
ele.addEventListener(evt, callback, false);
} else if (ele.length > 0) {
for (var i = 0; i < ele.length; i++) {
ele[i].addEventListener(evt, callback, false);
}
}
return false;
}
function getEle(ele) {
var _idf = ele.charAt(0);
if (_idf == "#") {
var _ele = document.getElementById(ele.substr(1));
return _ele;
} else if (_idf == ".") {
var _els = document.getElementsByClassName(ele.substr(1));
return _els;
}
return ele;
}
function getInnerHtml(id) {
return document.getElementById(id).innerHTML;
}
function getValue(elem) {
return elem.value;
}
setEvent("click", ".input", function() {
console.log(this.value);
var _num = getInnerHtml("math");
_num = _num + "" + getValue(this);
document.getElementById("math").innerHTML = _num;
});
It is a bit hard to understand what type of object model you're trying to build since you did not describe any requirements or desires in that regard. Here's one idea that kind of works like jQuery does:
function core(selector) {
if (!(this instanceof core)) {
return new core(selector);
}
var items = document.querySelectorAll(selector);
if (items) {
this.items = Array.prototype.slice.call(items);
} else {
this.items = [];
}
this.length = this.items.length;
return this;
}
core.prototype = {
each: function(fn) {
for (var i = 0; i < this.length; i++) {
fn.call(this.items[i]);
}
return this;
},
firstProp: function(propName, defaultVal) {
if (this.length > 0) {
var val = this.items[0][propName];
return val !== undefined ? val : defaultVal;
} else {
return defaultVal;
}
},
getHTML: function() {
return this.firstProp("innerHTML", "");
},
setHTML: function(html) {
return this.each(function() {
this.innerHTML = html;
});
},
on: function(event, fn) {
return this.each(function() {
this.addEventListener(event, fn);
});
},
getValue: function() {
return this.firstProp("value", "");
}
};
And, then a usage example like yours:
core(".input").on("click", function(e) {
console.log(this.value);
var math = core("#math");
math.setHTML(math.getHTML() + this.value);
});
Working demo: http://jsfiddle.net/jfriend00/t56L4p5f/