Marco Gasi
asked on
Recursively filtering Javascript object
Hi everybody.
I'm still fighting with Javascript - I ususally do it :)
So, now I0m trying to recursively loop through an object to see if any property contains a string. I tried many pieces of code, but here I report two of them. Both give the same error:
snippet 1
Snippet 2
The error is "TypeError: token is undefined" related to line 4 in the Snippet 1 and line 7 in the Snippet 2.
The calling handler event is as follows:
Any idea?
Thank you so much for any help.
I'm still fighting with Javascript - I ususally do it :)
So, now I0m trying to recursively loop through an object to see if any property contains a string. I tried many pieces of code, but here I report two of them. Both give the same error:
snippet 1
function iterate(obj, token) {
var cardsFound = [];
Object.keys(obj).forEach(function (key) {
if ($(obj[key]).toLocaleString().toLowerCase().indexOf(token.toLowerCase()) > -1) {
cardsFound.push(obj);
}
if (typeof obj[key] === 'object') {
iterate(obj[key]);
}
});
return cardsFound;
}
Snippet 2
function eachRecursive(obj, token) {
var cardsFound = [];
for (var k in obj) {
if (typeof obj[k] == "object" && obj[k] !== null) {
eachRecursive(obj[k]);
} else {
if (obj[k].toLocaleString().toLowerCase().indexOf(token.toLowerCase()) > -1) {
cardsFound.push(obj);
}
}
}
return cardsFound;
}
The error is "TypeError: token is undefined" related to line 4 in the Snippet 1 and line 7 in the Snippet 2.
The calling handler event is as follows:
$('#searchButton').on('click', function (e) {
e.preventDefault();
var sSearch = $('#searchbox').val();
alert(sSearch);
$('#card-wrapper').empty();
console.log(cards);
var foundCards = [];
foundCards = eachRecursive(cards, sSearch);
// foundCards = iterate(cards, sSearch);
console.log(foundCards);
});
Any idea?
Thank you so much for any help.
could you post an object and a string ?
ASKER
Hi leakim971.
Of course, I can and I do. But I'm trying to build a generic function I can use with whatever json object regardless of its properties' names.
This is the object:
My goal is to return all object which contains the string 'antinori' in any of its properties; the search should be case insensitive.
Thank you for you help :)
Of course, I can and I do. But I'm trying to build a generic function I can use with whatever json object regardless of its properties' names.
This is the object:
[
{
"ref": "1",
"tableName": "orders",
"id": "1",
"customer": "Webintenerife",
"orderNumber": "PIN00000002",
"date": "24/06/2019",
"product": [
{
"Name": "ANTINORI CHIANTI CLASSICO 750ML",
"Qt": "2"
},
{
"Name": " ANTINORI MARCHESE CUVEE ROYAL 750ML",
"Qt": " 3"
},
{
"Name": " CAFFE ESPRESSO ITA. 1KG GRANI",
"Qt": " 1"
},
{
"Name": " CAFFE ILLY CLASSICO 250GR",
"Qt": " 1"
}
],
"totalPrice": "153,76 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000002_2406201943.pdf'>PIN00000002_2406201943.pdf</a>"
},
{
"ref": "21",
"tableName": "orders",
"id": "21",
"customer": "Webintenerife",
"orderNumber": "PIN00000022",
"date": "26/06/2019",
"product": [
{
"Name": "CAFFE ESPRESSO ITA. 1KG GRANI",
"Qt": "1"
}
],
"totalPrice": "8,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000022_2606201922.pdf'>PIN00000022_2606201922.pdf</a>"
},
{
"ref": "22",
"tableName": "orders",
"id": "22",
"customer": "Webintenerife",
"orderNumber": "PIN00000023",
"date": "26/06/2019",
"product": [
{
"Name": "CAFFE ESPRESSO ITA. 1KG GRANI",
"Qt": "2"
},
{
"Name": " ANTINORI CERVARO DELLA SALA 750ML",
"Qt": " 1"
}
],
"totalPrice": "66,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000023_2606201948.pdf'>PIN00000023_2606201948.pdf</a>"
},
{
"ref": "23",
"tableName": "orders",
"id": "23",
"customer": "Webintenerife",
"orderNumber": "PIN00000024",
"date": "27/06/2019",
"product": [
{
"Name": "CAFFE ESPRESSO ITA. 1KG GRANI",
"Qt": "1"
}
],
"totalPrice": "8,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000024_2706201941.pdf'>PIN00000024_2706201941.pdf</a>"
},
{
"ref": "24",
"tableName": "orders",
"id": "24",
"customer": "Webintenerife",
"orderNumber": "PIN00000025",
"date": "30/06/2019",
"product": [
{
"Name": "AGROMONTE CILIEGINO 330GR",
"Qt": "1"
},
{
"Name": " AGROMONTE CILIEGINO BIO 250GR",
"Qt": " 1"
},
{
"Name": " CIRIO SUPERCONCENTRATO 140",
"Qt": " 1"
},
{
"Name": " DAVIA pomodorinini gragnano",
"Qt": " 1"
}
],
"totalPrice": "5,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000025_3006201940.pdf'>PIN00000025_3006201940.pdf</a>"
},
{
"ref": "25",
"tableName": "orders",
"id": "25",
"customer": "Webintenerife",
"orderNumber": "PIN00000026",
"date": "30/06/2019",
"product": [
{
"Name": "ANTINORI MARCHESE CUVEE ROYAL 750ML",
"Qt": "1"
},
{
"Name": " ANTINORI CHIANTI CLASSICO 750ML",
"Qt": " 1"
},
{
"Name": " ANTINORI VILLA ANTINORI BIANCO 750ML",
"Qt": " 1"
},
{
"Name": " ANTINORI VILLA ANTINORI ROSSO 750ML",
"Qt": " 1"
}
],
"totalPrice": "86,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000026_3006201904.pdf'>PIN00000026_3006201904.pdf</a>"
},
{
"ref": "26",
"tableName": "orders",
"id": "26",
"customer": "Webintenerife",
"orderNumber": "PIN00000027",
"date": "30/06/2019",
"product": [
{
"Name": "CAFFE IULIANO GRAN AROMA 250GR",
"Qt": "1"
},
{
"Name": " CAFFE IULIANO INTENSO 1KG GRANI",
"Qt": " 1"
}
],
"totalPrice": "10,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000027_3006201939.pdf'>PIN00000027_3006201939.pdf</a>"
},
{
"ref": "27",
"tableName": "orders",
"id": "27",
"customer": "Webintenerife",
"orderNumber": "PIN00000028",
"date": "30/06/2019",
"product": [
{
"Name": "CAFFE BORBONE MISCELA NOBILE 250GR",
"Qt": "1"
}
],
"totalPrice": "2,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000028_3006201953.pdf'>PIN00000028_3006201953.pdf</a>"
},
{
"ref": "28",
"tableName": "orders",
"id": "28",
"customer": "Webintenerife",
"orderNumber": "PIN00000029",
"date": "30/06/2019",
"product": [
{
"Name": "ANTINORI CHIANTI CLASSICO 750ML",
"Qt": "1"
}
],
"totalPrice": "26,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000029_3006201911.pdf'>PIN00000029_3006201911.pdf</a>"
},
{
"ref": "29",
"tableName": "orders",
"id": "29",
"customer": "Webintenerife",
"orderNumber": "PIN00000030",
"date": "30/06/2019",
"product": [
{
"Name": "CAFFE LAVAZZA ORO LATTA 250GR",
"Qt": "1"
},
{
"Name": " CAFFE LAVAZZA ORO 250GR",
"Qt": " 1"
}
],
"totalPrice": "11,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000030_3006201908.pdf'>PIN00000030_3006201908.pdf</a>"
},
{
"ref": "30",
"tableName": "orders",
"id": "30",
"customer": "Webintenerife",
"orderNumber": "PIN00000031",
"date": "30/06/2019",
"product": [
{
"Name": "CINZANO ASTI 75CL 7%VOL",
"Qt": "1"
},
{
"Name": " MARSALLA SUP. MARTINEZ SECCO 5 ANNI 18%VOL 750ML",
"Qt": " 1"
}
],
"totalPrice": "23,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000031_3006201925.pdf'>PIN00000031_3006201925.pdf</a>"
},
{
"ref": "31",
"tableName": "orders",
"id": "31",
"customer": "Webintenerife",
"orderNumber": "PIN00000032",
"date": "30/06/2019",
"product": [
{
"Name": "MUTTI CONCENTRATO VERDURINE 130GR",
"Qt": "1"
},
{
"Name": " MUTTI CILIEGINI 400GR",
"Qt": " 1"
}
],
"totalPrice": "2,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000032_3006201909.pdf'>PIN00000032_3006201909.pdf</a>"
},
{
"ref": "32",
"tableName": "orders",
"id": "32",
"customer": "Webintenerife",
"orderNumber": "PIN00000033",
"date": "30/06/2019",
"product": [
{
"Name": "TORMARESCA CALAFURIA 1",
"Qt": "1"
},
{
"Name": "5LT",
"Qt": " 1"
}
],
"totalPrice": "46,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000033_3006201926.pdf'>PIN00000033_3006201926.pdf</a>"
},
{
"ref": "33",
"tableName": "orders",
"id": "33",
"customer": "Webintenerife",
"orderNumber": "PIN00000034",
"date": "01/07/2019",
"product": [
{
"Name": "CAFFE ESPRESSO ITA. 1KG GRANI",
"Qt": "1"
}
],
"totalPrice": "8,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000034_0107201936.pdf'>PIN00000034_0107201936.pdf</a>"
},
{
"ref": "34",
"tableName": "orders",
"id": "34",
"customer": "Webintenerife",
"orderNumber": "PIN00000035",
"date": "01/07/2019",
"product": [
{
"Name": "ANTINORI CHIANTI CLASSICO 750ML",
"Qt": "1"
},
{
"Name": " ANTINORI CERVARO DELLA SALA 750ML",
"Qt": " 1"
},
{
"Name": " ANTINORI MARCHESE CUVEE ROYAL 750ML",
"Qt": " 1"
}
],
"totalPrice": "103,00 EUR",
"document": "<a class='col-light-blue' href='/orders/PIN00000035_0107201905.pdf'>PIN00000035_0107201905.pdf</a>"
}
]
My goal is to return all object which contains the string 'antinori' in any of its properties; the search should be case insensitive.
Thank you for you help :)
so you want a function returning an array like this one, no matter what object is sent :
[
{
"Name": "ANTINORI CHIANTI CLASSICO 750ML",
"Qt": "2"
},
{
"Name": " ANTINORI MARCHESE CUVEE ROYAL 750ML",
"Qt": " 3"
}
.......
{
"Name": "ANTINORI CHIANTI CLASSICO 750ML",
"Qt": "1"
},
{
"Name": "ANTINORI CHIANTI CLASSICO 750ML",
"Qt": "2"
},
{
"Name": " ANTINORI MARCHESE CUVEE ROYAL 750ML",
"Qt": " 3"
}
]
ASKER
No, not exactly. I already have got that. As you can see, the json represent an array of objects (let's call them cards) and each card has a property which is an array of objects.
I want to iterate through the whole collection and if the token is found I want add the card object where the token is to the resulting array of objects.
So in this case the result should be an array of 5 cards with all their properties. I'm trying right now to understand how to get if an object is child of another object in order to differtiate the code in the loop...
EDIT: and I don't understand why token is undefined since it is one function param...
I want to iterate through the whole collection and if the token is found I want add the card object where the token is to the resulting array of objects.
So in this case the result should be an array of 5 cards with all their properties. I'm trying right now to understand how to get if an object is child of another object in order to differtiate the code in the loop...
EDIT: and I don't understand why token is undefined since it is one function param...
Marco
Have a look here http://techslides.com/how-to-parse-and-search-json-in-javascript for how to recursively search a JSON object.
Have a look here http://techslides.com/how-to-parse-and-search-json-in-javascript for how to recursively search a JSON object.
ASKER
Thank you Norie. It looks interesting. I'll work on it to see if I can modify to avoid to pass key because I want a code I can use with any json object without knowing its properties.
I'll let you know results. Thanks for trying to help :)
I'll let you know results. Thanks for trying to help :)
I don't understand why the token is undefined since it is one function param...
To answer your last question you can see that you're not passing the token to the function so why you expect from it to be defined?
eachRecursive(obj[k]);
The function expects two parameters but receives just the first obj :
eachRecursive(obj, token)
ASKER
I have changed the function getObjects as follows:
Maybe I have to clarify.
I'm listing all orders stored in the table orders. I don't want to use a table (and the fantastic DataTables plugin) because cards are more mobile-friendly. So I have built cards, one card object for each order. Each card has a list of products stored in the array product; Each element in product is an object with a name and a quantity.
Every code I tried until now, if it was working, has given as result an array holding all products objects. I wants instead add the not the product objects but the card object they belong to.
Hope this help you all to help me :)
function getObjects(obj, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i))
continue;
if (typeof obj[i] === 'object') {
objects = objects.concat(getObjects(obj[i], val));
} else
if (obj[i].toLowerCase().indexOf(val) > -1) {
objects.push(obj);
} else if (obj[i].toLowerCase().indexOf(val) > -1) {
//only add if the object is not already in the array
if (objects.lastIndexOf(obj) === -1) {
objects.push(obj);
}
}
}
return objects;
}
It works but it adds all sub-objects which contain the string 'antinori'.Maybe I have to clarify.
I'm listing all orders stored in the table orders. I don't want to use a table (and the fantastic DataTables plugin) because cards are more mobile-friendly. So I have built cards, one card object for each order. Each card has a list of products stored in the array product; Each element in product is an object with a name and a quantity.
Every code I tried until now, if it was working, has given as result an array holding all products objects. I wants instead add the not the product objects but the card object they belong to.
Hope this help you all to help me :)
ASKER
Hi Zakaria. Oh, you're totally right, within the iteration I forgot to pass the token!!! I'going to fix this immediately and I'll let you know the result. Thank you!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hi Julian, my friend, how are you? Going to try that, thank you
ASKER
It works perfectly. But this way, the user can only filter the results per product name. I'm trying to allow the user to filter products per any properties without specifying it: it could type the client name, or the order number and the code should filter results accordingly...
But you made me make a step forward, thank you so much, Julian, you're great!!!
But you made me make a step forward, thank you so much, Julian, you're great!!!
That was just an illustration - just pass in whatever level you want to search on.
In my example I passed in i.product - but if you want to search the entire item then just pass in i
In my example I passed in i.product - but if you want to search the entire item then just pass in i
items.forEach(function(i) {
// Here we search the entire item
if (containsWord(i, 'antinori')) {
console.log(i, 'contains the word');
}
});
ASKER
Fantastic, Julian, you solved my problem!. Thank you very much.
And thank you all for trying to help me :)
And thank you all for trying to help me :)
ASKER
Thank you all, guys! But Julian code has solved my issue perfectly.
You are welcome.