If div children don't have same text content then do action - javascript

I'm trying to create DOM elements for an Ingredient filter bar, based on JSON file objects.
The problem is that the same ingredient can appear in several objects, and in that case it should only create the dom element once, not for each time the ingredient occures.
I've tried with childNode, value, innerHTML and !=== but can't figure out the solution. It either creates no element at all, or all of them with duplicates.
Any ideas?
Here is a codePen to help : https://codepen.io/enukeron/pen/eYdgyzx
I also tried with an array to keep track of seen values at this codepen :
https://codepen.io/enukeron/pen/ExgZoLa
JS:
const ingredientDropdown = document.getElementById('ingredientDropdown');
for(var j = 0; j < IngredientList.length; j++) {
if (ingredientDropdown.children.textContent !== IngredientList[j].ingredient) {
var ingredientSearchItems = document.createElement("p");
ingredientSearchItems.textContent = IngredientList[j].ingredient;
ingredientDropdown.appendChild(ingredientSearchItems);
}
}
The JSON file has this format :
{
"id": 49,
"name": "Tropical smoothie",
"servings": 4,
"ingredients": [
{
"ingredient": "Bananas",
"quantity": 2
},
{
"ingredient": "Kiwis",
"quantity": 3
},
{
"ingredient": "Mango",
"quantity": 1
},
{
"ingredient": "Pineapple",
"quantity": 4,
"unit":"slices"
},
{
"ingredient": "Honey",
"quantity": 2,
"unit": "tablespoons"
}
],
"time": 0,
"description":"Chop the fruit. Liquefy in the blender. Chill. Serve",
"appliance": "Blender",
"ustensils":["couteau", "verres"]
}, etc.....
The actual result is :
The Expected Result is :

You could create a function like the following:
function filterIngredients(recipes){
let return_arr = [];
recipes.forEach((recipe, index, array)=>{
let ingredients = recipe["ingredients"];
ingredients.forEach((ingredient, index, inner_array)=>{
if(!return_arr.includes(ingredient["ingredient"])){
return_arr.push(ingredient["ingredient"]);
}
});
});
return return_arr;
}
And then call the function as follows:
var ingredients = filterIngredients(recipes);
You can then loop through ingredients and display them in the div as you want (hoping this is what you wanted in the first place).
Here is a link to my pen where I implemented it:
https://codepen.io/AnirudhMS/pen/MWjJQgg?editors=1010

Related

React element - array objects only returning first item?

I am trying to retrieve item values from an object containing several items. The object is an array object. I am puzzled by only being able to retrive the first item and its values in each array instead of all items. Can anybody tell me what I am missing here.
The array object example:
{ "ITEM 1": [
{
"id": 123,
"name": "item1a"
},
{
"id": 234,
"name": "item1b"
},
{
"id": 345,
"name": "item1c"
}
],
"ITEM 2": [
{
"id": 456,
"name": "item2a"
},
{
"id": 567,
"name": "item2b"
},
{
"id": 678,
"name": "item2c"
}],
}
I have data within the new element and on debugging see that loop flows correctly but for some reason only the first item is rendered.
My code that is wrapped in an html element is as follows:
{ Object.keys(this.props.data).map(function (key) {
var list = component.props.data[key];
for (i = 0; i < facetParent.length; i++) {
var item = list[i];
return (
<CheckBox
key={item.id}
data={item}
name={item.name} />
)
}}, this)}
Any suggestions are much appreciated.
The return function immediately terminates the function execution. That is why you only get the first item. Depending on what version of react you use, you should create 2 arrays and join them before rendering

same item added multiple times in a array while using push or concat in Node JS

I am trying to push items into an array using for loop and wanted to use the filled in array. The 'push' or 'concat' happens successfully. But the problem is when there are two items looped in, the second time when the loop run pushes the second time twice in inside the array, instead of concatenating with the first item that is loop.
var response_items = {};
var basketItems = [];
for (var i = 0; i < basketRequest.items.length; i++) {
basket_item_code = basketRequest.items[i].item_code;
response_items.item_code = basket_item_code;
basket_item_price = basketRequest.items[i].price;
response_items.price = basket_item_price;
basket_item_qty = basketRequest.items[i].qty;
response_items.qty = basket_item_qty;
item_sub_total = basket_item_price * basket_item_qty;
sub_total = sub_total + item_sub_total;
response_items.fee = '800';
basketItems.push(response_items);
//basketItems= basketItems.concat(response_items);
console.log (i,'basketItems concatetw ...', basketItems);
}
Current Input
"items":[{
"item_code": "234234",
"price": "908",
"qty": "5"
},
{
"item_code": "787878777",
"price": "1008",
"qty": "5"
}]
Current O/p:
"items": [
{
"item_code": "787878777",
"price": "1008",
"qty": "5",
"fee": "800"
},
{
"item_code": "787878777",
"price": "1008",
"qty": "5",
"fee": "800"
}
]
Desired O/p:
"items":[{
"item_code": "234234",
"price": "908",
"qty": "5"
},
{
"item_code": "787878777",
"price": "1008",
"qty": "5"
}]
Youre putting the same object into the array multiple times. However your code isnt really readable. Thats how i would do it:
var basket_items = basketRequest.items.map(basket=>({
item_code:basket.item_code,
price:basket.price,
qty:basket.qty,
sub_total:(+basket.sub_total ||0) + basket.price * basket.qty,
fee:'800'
}));
Note that you need to convert sub_total to a number (+), and it doesnt appear in your input.
http://jsbin.com/pudapujaca/edit?console
Right now, you are putting the same object reference in the array and then changing the data in the object. So it changes in both places. You need to put the response_items object declaration inside the loop so that a new object is created and added to the array for each iteration.

How to determine the value in array which is in an object?

I get 100 objects (JSON) from a website, which is build like this.
"object" : [{
"id": 12243,
"name": 'Carl',
"text": 'subheader',
"tags": ["cars","child", "blue"],
...
},
{
"id": 12245,
"name": 'Dark',
"text": 'subheader',
"tags": ["cars"],
...
}
...
]
I want to get only which has the tag child. How can I do it?
You could try something like this:
var objectsWithChild = json.object.filter(function(o){
return o.tags.includes("child");
});
where json is your json string.
Using Array.prototype.filter()
var objs = [{
"id": 12243,
"name": 'Carl',
"text": 'subheader',
"tags": ["cars","child", "blue"]
},
{
"id": 12245,
"name": 'Dark',
"text": 'subheader',
"tags": ["cars"]
}]
var objsWithTags = objs.filter(obj => obj.tags.indexOf('child') > -1);
console.log(objsWithTags);
Christos has a cleaner way to do it, but this way might be clearer to a beginner. One way to do it would be to use nested for loops.
var myObjects = []
for (var i = 0; i < data.object.length; i++) {
var ob = data.object[i];
for (var j = 0; j < ob.tags.length; j++) {
if (ob.tags[i] === "child") {
myObjects.push(ob);
}
}
}
There are probably multiple ways to implement this.
But the main ideas are mostly the same.
Here in textual form:
Define a container (an array for example) for your matched objects.
Loop through all objects.
Loop through all entries of your array "tags".
Check if you find your desired value "child".
Remember your found object by adding it to your container (array).

Javascript looping through elements and adding to table

I'm having trouble finding a solution that will help me loop through a bunch of elements and putting the chosen values into a table. I've been able to withdraw some values but the method isn't dynamic.
Here is an example:
var Table = {
"credit": {
"link": "site link",
"logoUrl": "logo url",
"message": "message"
},
"groups": [
{
"labels": [
{
"name": "Western Conference",
"type": "conference"
},
{
"name": "Central Division",
"type": "division"
}
],
"standings": [
{
"stats": [
{
"name": "gp",
"value": 20
},
{
"name": "w",
"value": 17
},
{
"name": "l",
"value": 0
},
{
"name": "gf",
"value": 64
},
{
"name": "ga",
"value": 37
},
{
"name": "gd",
"value": 27
},
{
"name": "pts",
"value": 37
}
],
"team": {
"id": 12345,
"link": "team link",
"name": "team name",
"shortName": "team"
}
},
This is the structure of the elements. So far I've used this:
document.getElementById("sGamesPlayed").innerHTML=Table.groups[0].standings[0].stats[0].value;
to withdraw values. However there are more teams, stats and divisions so I would need some kind of loop to go through the elements and put the into a dynamic table.
I would consider you to look at http://underscorejs.org/.
it provides a bunch of utility functions that could help you,
for example, _.each() helps you loop through JSON properties.
for the sample objects you've given (after completing the missing brackets at the end),
_.each(Table.groups[0].standings[0].stats, function(stats){
console.log(stats['name']+","+stats['value'])
})
gives me:
gp,20
w,17
l,0
gf,64
ga,37
gd,27
pts,37
how it works is that you provide the object you want as the first argument and the function that you give as the second argument will be called with each element of the first argument (Assuming it is a list).
I would also urge you to look at underscore templating that you can use to render your table where i put the console.log :
http://net.tutsplus.com/tutorials/javascript-ajax/getting-cozy-with-underscore-js/
http://scriptble.com/2011/01/28/underscore-js-templates/
I guess your question is about filtering the values of the array standings. In order to do that you can use the jQuery grep function (if you want to use jQuery).
For example you can write:
var arr = $.grep(Table.groups[0].standings[0].stats, function(d){return d.value>25})
Which will give
arr = [{"name": "gf","value": 64}, {"name": "ga", "value": 37},{"name": "gd", "value": 27},{"name": "pts", "value": 37}]
If this is not what you meant, can you please create a jsFiddle with a sample of what you want?
Depending on what you want to do with the results, you can go over the object using a scheme like:
var groups, standings, stats, value;
groups = Table.groups;
// Do stuff with groups
for (var i=0, iLen=groups.length; i<iLen; i++) {
standings = groups[i].standings;
// Do stuff with standings
for (var j=0, jLen=standings.length; j<jLen; j++) {
stats = standings[j];
// Do stuff with stats
for (var k=0, kLen=stats.length; k<kLen; k++) {
value = stats[k].value;
// Do stuff with value
}
}
}
Of course I have no idea what the data is for, what the overall structure is or how you want to present it. But if you have deeply nested data, all you can do is dig into it. You might be able to write a recursive function, but it might also become very difficult to maintain if the data structure is complex.

Javascript nested array transformation

I'm trying to get my head around Javascript array functions. I have a nested array like this, where every row covers the same time period:
[{
"category": "fruit",
"variety": "apple",
"data": [{
"day": 1,
"units": 2
}, {"day": 2,
"units": 4
}]
},{
"category": "fruit",
"variety": "orange",
"data": [{
"day": 1,
"units": 3
}, {"day": 2,
"units": 5
}]
},{
"category": "veg",
"variety": "tomato",
"data": [{
"day": 1,
"units": 4
}, {"day": 2,
"units": 2
}]
}]
I would like to sum the units by day by category, to get an array like this:
[{
"category": "fruit",
"data": [{
"day": 1,
"units": 5
}, {"day": 2,
"units": 9
}]
},{
"category": "veg",
"data": [{
"day": 1,
"units": 4
}, {"day": 2,
"units": 2
}]
}]
I've been tackling this through long looping if statements, and making a bit of a hash of it. Can you see an elegant way to solve this?
Many thanks!
The solution is pretty obvious: Loop through the array, and store the data in a key-value pair. Then, loop through the has, and construct the resulting array using Array.prototype.map. Finally, if you want a nicely formatted JSON-string, use JSON.stringify(result, null, 4);, where 4 is the number of spaced for pretty formatting.
Demo: http://jsfiddle.net/jde6S/
var list = [ ... ];
var hash = {};
for (var i=0; i<list.length; i++) {
var obj = list[i];
// This part makes sure that hash looks like {fruit:[], veg: []}
var hashObjCat = hash[obj.category];
if (!hashObjCat) {
hashObjCat = hash[obj.category] = {};
}
// This part populates the hash hashObjCat with day-unit pairs
for (var j=0; j<obj.data.length; j++) {
var data = obj.data[j];
if (hashObjCat[data.day]) hashObjCat[data.day] += data.units;
else hashObjCat[data.day] = data.units;
}
}
// Now, we hash looks like {fruit: {1:5, 2:9} }
// Construct desired object
var result = Object.keys(hash).map(function(category) {
// Initial object
var obj = {category: category, data:[]};
var dayData = Object.keys(hash[category]);
// This part adds day+units dicts to the data array
for (var i=0; i<dayData.length; i++) {
var day = dayData[i];
var units = hash[category][day];
obj.data.push({day: day, units: units});
}
return obj;
});
// Test:
console.log(JSON.stringify(result, null, 4));
reduce the array to an object (See #RobW's answer on how to do that with loops):
var data = [...] // your input
// Iterate the data with reduce...
var sumsbycategory = data.reduce(function(map, fruit) {
var cat = fruit.category;
// set an property to an object, iterating the days array...
map[cat] = fruit.data.reduce(function(sums, day) {
var d = day.day;
// set or update the units for this day
sums[d] = (sums[d] || 0) + day.units;
return sums; // into the next iteration
}, map[cat] || {}) // ...passing in the already existing map for this cat or a new one
return map; // into the next iteration
}, {}); // ...passing in an empty object
Now we have the following format:
{"fruit":{"1":5,"2":9},"veg":{"1":4,"2":2}}
...which I think is much easier to handle, but lets build your array:
var result = []; // init array
for (var cat in sumsbycategory) { // loop over categories
var data = []; // init array
// add category object:
result.push({category:cat, data:data});
for (var day in sumsbycategory[cat]) // loop over days in category
// add day object
data.push({day:day, units:sumsbycategory[cat][day]});
}
But, wait! An object has no order, and it could happen that day2 comes before days1 in the result array (which might break your appplication?) So, you could use map on the keys of that object which also can be sorted before, to generate the array in one clean-looking expression:
var result = Object.keys(sumsbycategory).map(function(cat) {
return {
category: cat,
data: Object.keys(sumsbycategory[cat])
.sort(function numbercompare(a,b){ return a-b; })
.map(function(day) {
return {
day: day,
units: sumsbycategory[cat][day]
};
})
};
});
result:
[{
"category": "fruit",
"data": [{"day":"1","units":5},{"day":"2","units":9}]
},{
"category": "veg",
"data": [{"day":"1","units":4},{"day":"2","units":2}]
}]
(Demo at jsfiddle.net)
If you're willing to grab some external code and use it to essentially re-index your structure you could probably do something. I know the old dojo data api was a mess to work with, but could allow something like what you seem to be asking.
Personally I'd stick with loops, just keep your variable names readable. Also remember the object literals can be addressed as either an array/hash syntax x[y] or dot syntax x.y

Categories

Resources