JavaScript - how do i do the splice of a multidimensional array? - javascript

How do i delete the 'test1' from db using the del function?
var db = [];
function add(input) {
for(var key in db) {
if(db[key][0]===input[0]) {
return;
}
}
db[db.length] = input;
}
function edit(input, upgrade) {
for(var key in db) {
if(db[key][0]===input) {
db[key] = upgrade;
}
}
}
function del(input) {
var index = db.indexOf(input);
if (index !== -1) {
db.splice(index, 1);
}
}
add(['test1', 'online']);
console.log(db);
edit('test1', ['test1','offline']);
console.log(db);
del('test1'); // FAILED still shows old values
console.log(db);

The actual problem is not with the splice but with the indexOf. It will return the index of the item, only if the item being searched is the same as the object in the array. So, you have to roll your own search function, like this
function del(input) {
var i;
for (i = 0; i < db.length; i += 1) {
if (db[i][0] === input) {
db.splice(i, 1);
return;
}
}
}
Note: Never iterate an array with for..in. Use normal for loop.

Related

Find in object to Edit or Add

I have an object productCounts
[{provisioned=2.0, product=str1, totalID=1.0},
{product=str2, provisioned=4.0, totalID=3.0},
{provisioned=6.0, product=str3, totalID=5.0}]
I have an array uniqueProduct
[str1, str2, str3, str4]
I am then looping a dataset to get the totalID count, add it to the product's totalID but if it doesn't exist, push it to the object.
var countID = 0;
uniqueProduct.forEach(
currentproduct => {
countID = 0;
for (var i = 0; i < shtRng.length; ++i) {
if (shtRng[i][ProductCol].toString() == currentproduct) { // && shtRng[i][IDcol].toString().length>4){
countID++;
}
}
if (countID == 0) {
return;
}
console.log(currentproduct + ": " + countID);
}
)
This works perfectly to return the countID per product in uniqueProduct
Rather than logging the result, I would like to add it to the object like this... If the current unique product is not in the productCounts object, add it.
let obj = productCounts.find((o, i) => {
if (o.product == currentproduct) {
productCounts[i] = { product: currentproduct, totalID: productCounts[i].totalID+countID, provisioned: productCounts[i].provisioned };
return true;
} else {
productCounts.push({ product: currentproduct, totalID: countID, provisioned: 0 });
return true;
}
});
In my head, this should work but it appears to skip some records or add the product multiple times. How do I add to the object correctly?
Expected output is the object to be something similar to:
[{provisioned=2.0, product=str1, totalID=35.0},
{product=str2, provisioned=4.0, totalID=8.0},
{provisioned=6.0, product=str3, totalID=51.0},
{provisioned=6.0, product=str4, totalID=14.0}]
The argument to find() is a function that returns a boolean when the element matches the criteria. The if statement should use the result of this, it shouldn't be in the condition function.
let obj = productCounts.find(o => o.product == currentProduct);
if (obj) {
obj.totalId += countID;
} else {
productCounts.push(productCounts.push({ product: currentproduct, totalID: countID, provisioned: 0 });
}
BTW, your life would be easier if you used an object whose keys are the product names, rather than an array of objects. You can easily turn the array of objects into such an object:
let productCountsObj = Object.fromEntries(productCounts.map(o => [o.product, o]));
if (currentProduct in productCountsObj) {
productCountsObj[currentProduct].totalID += countID;
} else {
productCountsObj[currentProduct] = { product: currentproduct, totalID: countID, provisioned: 0 };
}

es6 code broken in es5

I have been trying to translate my code from es6 to es5 because of some framework restrictions at my work... Although I have been quite struggling to locate what the problem is. For some reason the code does not work quite the same, and there is no errors either ...
Can someone tell me If I have translated properly ?
This is the ES6 code :
function filterFunction(items, filters, stringFields = ['Title', 'Description'], angular = false) {
// Filter by the keys of the filters parameter
const filterKeys = Object.keys(filters);
// Set up a mutable filtered object with items
let filtered;
// Angular doesn't like deep clones... *sigh*
if (angular) {
filtered = items;
} else {
filtered = _.cloneDeep(items);
}
// For each key in the supplied filters
for (let key of filterKeys) {
if (key !== 'TextInput') {
filtered = filtered.filter(item => {
// Make sure we have something to filter by...
if (filters[key].length !== 0) {
return _.intersection(filters[key], item[key]).length >= 1;
}
return true;
});
}
// If we're at TextInput, handle things differently
else if (key === 'TextInput') {
filtered = filtered.filter(item => {
let searchString = "";
// For each field specified in the strings array, build a string to search through
for (let field of stringFields) {
// Handle arrays differently
if (!Array.isArray(item[field])) {
searchString += `${item[field]} `.toLowerCase();
} else {
searchString += item[field].join(' ').toLowerCase();
}
}
// Return the item if the string matches our input
return searchString.indexOf(filters[key].toLowerCase()) !== -1;
});
}
}
return filtered;
}
And this is the code I translated that partially 99% work ..
function filterFunction(items, filters, stringFields, angular) {
// Filter by the keys of the filters parameter
var filterKeys = Object.keys(filters);
// Set up a mutable filtered object with items
var filtered;
// Angular doesn't like deep clones... *sigh*
if (angular) {
filtered = items;
} else {
filtered = _.cloneDeep(items);
}
// For each key in the supplied filters
for (var key = 0 ; key < filterKeys.length ; key ++) {
if (filterKeys[key] !== 'TextInput') {
filtered = filtered.filter( function(item) {
// Make sure we have something to filter by...
if (filters[filterKeys[key]].length !== 0) {
return _.intersection(filters[filterKeys[key]], item[filterKeys[key]]).length >= 1;
}
return true;
});
}
// If we're at TextInput, handle things differently
else if (filterKeys[key] === 'TextInput') {
filtered = filtered.filter(function(item) {
var searchString = "";
// For each field specified in the strings array, build a string to search through
for (var field = 0; field < stringFields.length; field ++) {
// Handle arrays differently
console.log(field);
if (!Array.isArray(item[stringFields[field]])) {
searchString += item[stringFields[field]] + ' '.toLowerCase();
} else {
searchString += item[stringFields[field]].join(' ').toLowerCase();
}
}
// Return the item if the string matches our input
return searchString.indexOf(filters[filterKeys[key]].toLowerCase()) !== -1;
});
}
}
return filtered;
}
These two lines
searchString += `${item[field]} `.toLowerCase();
searchString += item[stringFields[field]] + ' '.toLowerCase();
are not equivalent indeed. To apply the toLowerCase method on all parts of the string, you'll need to wrap the ES5 concatenation in parenthesis:
searchString += (item[stringFields[field]] + ' ').toLowerCase();
or, as blanks cannot be lowercased anyway, just use
searchString += item[stringFields[field]].toLowerCase() + ' ';
Here is a translated code from babeljs itself, as commented above.
'use strict';
function filterFunction(items, filters) {
var stringFields = arguments.length <= 2 || arguments[2] === undefined ? ['Title', 'Description'] : arguments[2];
var angular = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
// Filter by the keys of the filters parameter
var filterKeys = Object.keys(filters);
// Set up a mutable filtered object with items
var filtered = void 0;
// Angular doesn't like deep clones... *sigh*
if (angular) {
filtered = items;
} else {
filtered = _.cloneDeep(items);
}
// For each key in the supplied filters
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
var _loop = function _loop() {
var key = _step.value;
if (key !== 'TextInput') {
filtered = filtered.filter(function (item) {
// Make sure we have something to filter by...
if (filters[key].length !== 0) {
return _.intersection(filters[key], item[key]).length >= 1;
}
return true;
});
}
// If we're at TextInput, handle things differently
else if (key === 'TextInput') {
filtered = filtered.filter(function (item) {
var searchString = "";
// For each field specified in the strings array, build a string to search through
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = stringFields[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var field = _step2.value;
// Handle arrays differently
if (!Array.isArray(item[field])) {
searchString += (item[field] + ' ').toLowerCase();
} else {
searchString += item[field].join(' ').toLowerCase();
}
}
// Return the item if the string matches our input
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return searchString.indexOf(filters[key].toLowerCase()) !== -1;
});
}
};
for (var _iterator = filterKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
_loop();
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return filtered;
}
p.s. Or there is a better way to use babeljs directly without manually converting it.

javascript remove item from array, if an item already existing in array

following adds items to array:
var arrayOptions = [];
function AddToFilterOptionList(mode) {
arrayOptions.push(mode);
}
remove item from array:
function RemoveFromFilterOptionList(mode) {
var index = arrayOptions.indexOf(mode);
if (index !== -1) {
arrayOptions.splice(index, 1);
}}
for example if i call
AddToFilterOptionList('APPLE') - APPLE should be added to array.
If i again call
AddToFilterOptionList('APPLE+FRUIT') - it should remove the the item 'APPLE' from array arrayOptions and should add APPLE+FRUIT
Any time only one word that starts with APPLE can be in array.
How to find the word like 'APPLE' in javascript.
I tried with Match() which returns the matching word. IndexOf() returns 1 only if whole word is match but not start of word.
Cycle through the Array and then use the startsWith method.
void AddToFilterOptionList(String mode) {
for (i=0; i<arrayOptions.length; i++) {
if (mode.startsWith(arrayOptions[i] == 1)) {
array[i] = mode;
return; // found, so return
}
}
arrayOptions.push(mode); // should only get here if string did not exist.
}
You need to split by + characted and then loop over produced array to add/remove all items:
var arrayOptions = [];
function AddToFilterOptionList(mode) {
mode.split(/\+/g).forEach(function(el) {
var index = arrayOptions.indexOf(el);
if (index !== -1) {
arrayOptions.splice(index, 1);
}
else {
arrayOptions.push(el);
}
});
}
function RemoveFromFilterOptionList(mode) {
var index = arrayOptions.indexOf(mode);
if (index !== -1) {
arrayOptions.splice(index, 1);
}
}
AddToFilterOptionList('APPLE');
document.write('<p>' + arrayOptions); // expect: APPLE
AddToFilterOptionList('APPLE+FRUIT');
document.write('<p>' + arrayOptions); // expect: FRUIT
AddToFilterOptionList('APPLE+FRUIT+CARROT');
document.write('<p>' + arrayOptions); // expect: APPLE,CARROT
This will work assuming the 'this+that' pattern is consistent, and that we only care about the starting item.
http://jsbin.com/gefasuqinu/1/edit?js,console
var arr = [];
function remove(item) {
var f = item.split('+')[0];
for (var i = 0, e = arr.length; i < e; i++) {
if (arr[i].split('+')[0] === f) {
arr.splice(i, 1);
break;
}
}
}
function add(item) {
remove(item);
arr.push(item);
}
UPDATE:
function add (array, fruits) {
var firstFruit = fruits.split('+')[0]
var secondFruit = fruits.split('+')[1]
var found = false
var output = []
output = array.map(function (item) {
if (item.indexOf(firstFruit) > -1) {
found = true
return fruits
}
else return item
})
if (! found) {
array.push(fruits)
}
return output
}
var fruits = []
add(fruits, 'APPLE')
fruits = add(fruits, 'APPLE+GRAPE')
console.log(fruits[0]) // 'APPLE+GRAPE'
fruits = add(fruits, 'APPLE')
console.log(fruits[0]) // 'APPLE'
Try this, the code is not optimised though :P
<html>
<head>
<script src = "jquery-1.10.2.min.js"></script>
<script type = "text/javascript">
var itemList = [];
function addItem()
{
var item = $('#item').val();
if(item != '' || item != 'undefined')
{
if(itemList.length == 0)
itemList.push(item);
else
{
for(i=0;i<itemList.length;i++)
{
var splittedInputItems = [];
splittedInputItems = item.split("+");
var splittedListItems = [];
splittedListItems = itemList[i].split("+");
if(splittedListItems[0] == splittedInputItems[0])
{
itemList.splice(i,1);
itemList.push(item);
return;
}
}
itemList.push(item);
}
}
}
</script>
</head>
<body>
<input id="item" type = "text"/>
<input type = "button" value="Add" onclick="addItem()">
</body>
</html>
let items = [1, 2, 3, 2, 4, 5, 2, 7];
let item = 2;
for (let i = 0; i < items.length; i++) {
if (items[i] === item) {
items.splice(i, 1);
i = i - 1;
}
}
If you want to remove the element '2' from items array, it is a way.

Angularjs filtering json results

I'm having trouble filtering a json object using a filter function from a repeater. The filter was working on the first level without issue but now when I try to filter the rest of the collection and then return the scope data if the filter is not defined I get errors.
I've created a fiddle, I appreciate the help.
app.filter('showByfilValue',['ctrl'], function ($scope,ctrl) {
return function (items, word) {
var filtered = [];
if (typeof word !== 'undefined') {
var letterMatch = new RegExp('^' + word + '$', 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (letterMatch.test(item.services[0].services[0].serviceName)) {
filtered.push(item);
}
}
return filtered;
} else {
return data;
}
};
});
Jimi

Getting nested obj value

Given the following obj:
var inputMapping = {
nonNestedItem: "someItem here",
sections: {
general: "Some general section information"
}
};
I'm writing a function to get that data by passing in a string "nonNestedItem" or in the nested case "sections.general". I'm having to use an eval and I was wondering if there was maybe a better way to do this.
Here is what I have so far and it works okay. But improve!
function getNode(name) {
var n = name.split(".");
if (n.length === 1) {
n = name[0];
} else {
var isValid = true,
evalStr = 'inputMapping';
for (var i=0;i<n.length;i++) {
evalStr += '["'+ n[i] +'"]';
if (eval(evalStr) === undefined) {
isValid = false;
break;
}
}
if (isValid) {
// Do something like return the value
}
}
}
Linky to Jsbin
You can use Array.prototype.reduce function like this
var accessString = "sections.general";
console.log(accessString.split(".").reduce(function(previous, current) {
return previous[current];
}, inputMapping));
Output
Some general section information
If your environment doesn't support reduce, you can use this recursive version
function getNestedItem(currentObject, listOfKeys) {
if (listOfKeys.length === 0 || !currentObject) {
return currentObject;
}
return getNestedItem(currentObject[listOfKeys[0]], listOfKeys.slice(1));
}
console.log(getNestedItem(inputMapping, "sections.general".split(".")));
You don't need to use eval() here. You can just use [] to get values from an object. Use a temp object to hold the current value, then update it each time you need the next key.
function getNode(mapping, name) {
var n = name.split(".");
if (n.length === 1) {
return mapping[name];
} else {
var tmp = mapping;
for (var i = 0; i < n.length; i++) {
tmp = tmp[n[i]];
}
return tmp;
}
}

Categories