I would like to have a function called getSelectedValues which retrieves data from the options array instead of a variable called SelectedValues ( which is the way I have it now). The variable Selected Values currently gets the values that are true inside of the options array and assigns them to itself.
I simply would like to make this a function instead. (something called getSelectedValues I would imagine) How do I achieve this?
var options = [
{
name: "Red Pepper",
"selected": false,
value: "5.99"
},
{
name: "Garlic",
"selected": true,
value: "5.99"
},
{
name: "Tomatoes",
"selected": true,
value: "5.99"
},
]
var SelectedValues = options.filter(function (option) {
return (option.selected);
});
console.log(SelectedValues)
Just for reference, read more:
Declaring functions in JavaScript
function filterOptions(options) {
return options.filter(i => i.selected);
}
function filterOptions(options) {
return options.filter((i) => i.selected);
}
var options = [
{
name: "Red Pepper",
selected: false,
value: "5.99",
},
{
name: "Garlic",
selected: true,
value: "5.99",
},
{
name: "Tomatoes",
selected: true,
value: "5.99",
},
];
var selectedValues = filterOptions(options);
console.log(selectedValues);
.as-console {
min-height: 100% !important;
}
.as-console-row {
color: blue !important;
}
Something like this?
function getSelectedValues(options) {
const size = Object.keys(options).length;
for (var i = 0; i < size; i = i + 1) {
const isSelected = options[i]["selected"];
if (isSelected) {
alert(options[i].name);
}
}
}
Jsfiddle here: https://jsfiddle.net/z3nrh8Ly/50/
function getSelectedValues() {
return options.filter(t => t.selected);
}
another way:
getSelectedValues = () => options.filter(t => t.selected);
Related
filtervalue = {
serviceLine:['cca','ga']
}
this.inProgresDetailsData = [{serviceLine:'cca'}, { serviceLine:'cca'}, { serviceLine:'bca'}]
this.hrResourceDetailsdata= this.inProgresDetailsData.filter(item => {
for (let index = 0; index < filterValue.serviceLine.length; index++) {
item.serviceLine == filterValue.serviceLine[index]
}
});`
this.hrResourceDetailsdata is empty on filtering
The Array.prototype.filter (documentation) function expects you to return a boolean value that decides whether to keep the current item or not.
Since you are originally not returning any value, you implicitly return undefined which when checked against a boolean resolves to false, hence, all of your array items are discarded one by one, leaving none remaining.
You want to return the boolean to make this work:
this.hrResourceDetailsdata = this.inProgresDetailsData.filter(item => {
for (let index = 0; index < filterValue.serviceLine.length; index++) {
if (item.serviceLine == filterValue.serviceLine[index]) {
return true; // return true if found, otherwise continue
}
}
return false; // filter is never found in loop, fall back to false
});
Also, you can use Array.prototype.includes (documentation) to simplify your check, the following code does the exact same thing:
this.hrResourceDetailsdata = this.inProgresDetailsData.filter(item => {
// return true if `item.serviceLine` is inside `filterValue.serviceLine`
return filterValue.serviceLine.includes(item.serviceLine);
});
You can create a Set out of filterValue.serviceLine and filter out the items that are present in the set.
const
filterValue = { serviceLine: ["cca", "ga"] },
inProgressDetailsData = [
{ serviceLine: "cca" },
{ serviceLine: "cca" },
{ serviceLine: "bca" },
],
filterSet = new Set(filterValue.serviceLine),
hrResourceDetailsdata = inProgressDetailsData.filter(({ serviceLine }) =>
filterSet.has(serviceLine)
);
console.log(hrResourceDetailsdata);
If you want to apply multiple filters, then:
Create an object containing filters in form of Sets.
Filter items where all the filters are applicable using Array.prototype.every.
const
filterValue = {
serviceLine: ["cca", "ga"],
urgency: ["medium", "high"],
},
filterSet = Object.fromEntries(
Object.entries(filterValue).map(([k, v]) => [k, new Set(v)])
),
inProgressDetailsData = [
{ id: 1, urgency: "low", serviceLine: "cca" },
{ id: 2, urgency: "medium", serviceLine: "cca" },
{ id: 3, urgency: "low", serviceLine: "bca" },
{ id: 4, urgency: "high", serviceLine: "ga" },
{ id: 5, urgency: "low", serviceLine: "abc" },
],
hrResourceDetailsdata = inProgressDetailsData.filter((data) =>
Object.entries(filterSet).every(([k, v]) => v.has(data[k]))
);
console.log(hrResourceDetailsdata);
Code
filtervalue = {
serviceLine:['cca','ga']
};
this.inProgresDetailsData = [
{ serviceLine:'cca'},
{ serviceLine:'cca'},
{ serviceLine:'bca'}
];
this.hrResourceDetailsdata = this.inProgresDetailsData.filter(item => {
return filtervalue.serviceLine.includes(item.serviceLine)
});
console.log(this.hrResourceDetailsdata)
Hi I have object like this:
Subject {
id:1
packages: [
{id:1, isChecked:true, ...},
{id:2, isChecked:false, ...},
{id:3, isChecked:true, themes:[
{id:1, isChecked:true},
{id:1, isChecked:false},
]
]
...
}
How can i remove all not checked items from this object please? I have to send this updated object to another component in react app.
The real tree looks like this:
Subject
|-packages
|-themes (check if checked)
|-themeParts (check if checked)
|-exercises (check if checked)
If any of child is checked it should be added to new component. So if I have Two packages and only one exercise is checked it is also checked themmeparts of this exercise, also theme of theme part and theme. Packages don't have isChecked attribute but i have to add this level to new object too if any of its child is checked.
Other example... if second package has no theme,part or exercise checked i have to remove from package level down alll...
So when i finish i need to have only Subject{} object with checked items + package of that checked items...
I hope i described it good XD....
anyway i tried something like this:
returnSelectedItems(){
console.log(this.state.data);
let newData = cloneDeep(this.state.data);
newData.packages = [];
this.state.data.packages.forEach((pckg) => {
const newPackage = {
};
pckg.themes.forEach((theme, key) => {
if(theme.isChecked){
}
});
});
console.log(newData);
console.log(newData.packages);
console.log(newData.packages[0].themes);
console.log(newData.packages[0].themes[0].themeParts);
}
But this is useless i think and i really don't know how to od it properly and ezy as it can be.. Thx for help
You can create a generic function like this. This takes an array as input and reduces it recursively for any nested array property. Destructure the object and get the array property to a rest object. If the rest object has any keys, recursively call the function to filter for the isChecked property.
This will work for any name of the array property for any number of nesting
function getChecked(array) {
return array.reduce((acc, { id, isChecked, ...rest }) => {
if (isChecked) {
const o = { id, isChecked };
const [key] = Object.keys(rest);
if (key)
o[key] = getChecked(rest[key]);
acc.push(o)
}
return acc;
}, [])
}
const output = {
id: input.id,
packages: getChecked(input.packages)
};
Here's a snippet:
function getChecked(array) {
return array.reduce((acc, { id, isChecked, ...rest }) => {
if (isChecked) {
const o = { id, isChecked };
const [key] = Object.keys(rest);
if (key)
o[key] = getChecked(rest[key]);
acc.push(o)
}
return acc;
}, [])
}
const input = {
id: 1,
packages: [
{ id: 1, isChecked: true },
{ id: 2, isChecked: false },
{ id: 3, isChecked: true, themes: [
{
id: 4, isChecked: true, themeParts: [
{ id: 5, isChecked: true, exercises: [
{ id: 7, isChecked: true },
{ id: 8, isChecked: false }
]
},
{ id: 6, isChecked: true }
]
},
{ id: 9, isChecked: false }
]
},
{ id: 10, isChecked: true },
]
};
const output = {
id: input.id,
packages: getChecked(input.packages)
};
console.log(output)
I believe this is what you want. That's parent cannot be removed if children(themes) need to be kept
var subjects = {
id: 1,
packages: [{
id: 1,
isChecked: true,
},
{
id: 2,
isChecked: false,
},
{
id: 3,
isChecked: true,
themes: [{
id: 1,
isChecked: true
},
{
id: 1,
isChecked: false
},
]
}
]
};
function purge(item) {
purgeItems(item.themes ||[]);
return !item.isChecked && (item.themes ||[]).length === 0;
}
function purgeItems(themes) {
var toremove = [];
themes.forEach(function(p, i) {
if (purge(p)) {
toremove.push(i)
}
});
while (toremove.length > 0) {
themes.splice(toremove.pop(), 1);
}
}
purgeItems(subjects.packages);
console.log(JSON.stringify(subjects));
This is what i needed. using this principe: let {packages: packages, ...newData} = tempData;
returnSelectedItems(){
let tempData = cloneDeep(this.state.data);
let {packages: packages, ...newData} = tempData;
this.state.data.packages.forEach(pckg => {
const {themes,...newPckg} = pckg;
newPckg.themes = [];
pckg.themes.forEach(theme =>{
if(!theme.isChecked){
return;
}
const {themeParts, ...newTheme} = theme;
newTheme.themeParts =[];
newPckg.themes.push(newTheme);
theme.themeParts.forEach(part =>{
if(!part.isChecked){
return;
}
const {knowledges, ...newPart} = part;
newPart.knowledges = [];
newTheme.themeParts.push(newPart);
part.knowledges.forEach(knowledge =>{
if(!knowledge.isChecked){
return;
}
newPart.knowledges.push(knowledge);
});
});
});
if(newPckg.themes.length > 0){
newData.packages = newPckg;
}
});
return newData;
}
I am struggling to add a field to an map in an array. I am trying to add "canAssist": false to each map in the array for each of the countries.
Here is my database:
[
{
"Afghanistan": {
"country": "Afghanistan",
"countryCode": "AF",
"countryCodeAlt": "AFG",
"emoji": "🇦🇫",
"packages": [
{
"name": "Luxury Couple",
"cost": "$2000.00",
// I want to add canAssist:false here!
},
{
"name": "Quick Retreat",
"cost": "$1000.00",
// I want to add canAssist:false here!
}
]
}
},
{...}
{...}
]
This is what I've tried:
let travelData = database.collection('countries').doc(docName);
travelData.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(array) {
packages.map(package => {
return package.add({
canAssist: false
});
})
});
});
You can use Object.values() and object destructuring to achieve this.
const querySnapshot = [
{
Afghanistan: {
country: 'Afghanistan',
countryCode: 'AF',
countryCodeAlt: 'AFG',
emoji: '🇦🇫',
packages: [
{
name: 'Luxury Couple',
cost: '$2000.00',
// I want to add canAssist:false here!
},
{
name: 'Quick Retreat',
cost: '$1000.00',
// I want to add canAssist:false here!
},
],
},
},
{
...
},
{
...
},
];
const updateSnapshot = (snapshot, newData) => {
return snapshot.map(countryData => {
// only one field with the name of the country
const country = Object.values(countryData)[0];
let updatedCountry = { ...country };
const field = country[newData.field];
if (field) {
if (typeof field === 'string') {
updatedCountry[newData.field] = newData.values;
} else if (Array.isArray(field)) {
updatedCountry[newData.field] = field.map(data => ({ ...data, ...newData.values }));
}
}
return { [updatedCountry.country]: updatedCountry };
});
};
(() => {
console.log('Original', JSON.stringify(querySnapshot, null, 4));
const updatedSnapshot = updateSnapshot(querySnapshot, { field: 'packages', values: { canAssist: false } });
console.log('Updated', JSON.stringify(updatedSnapshot, null, 4));
const updatedSnapshot2 = updateSnapshot(querySnapshot, { field: 'emoji', values: '🇪🇸' });
console.log('Spanish!', JSON.stringify(updatedSnapshot2, null, 4));
})();
Of course, you don't need to have that dynamism with the 'newData', I just added in case you want to play around any field of your datasource.
I am trying to create an object from a forEach loop in javascript and in this simple object, I am trying to add up all of the counts for each item in the array.
Currently, I'm using firebase in an ionic (angular/typescript) project and I am returning an array of items from firebase. The array looks something like this:
[
{
id:'uniqueID',
specs: {
count:5,
forSale:false,
group:"qPELnTnwGJEtJexgP2qX",
name:"Foxeer Cam 2",
type:"camera"
}
},
{
id:'uniqueID',
specs: {
count:4,
forSale:false,
group:"qPELnTnwGJEtJexgP2qX",
name:"Furibee 40a",
type:"esc"
}
},
{
id:'uniqueID',
specs: {
count:4,
forSale:false,
group:"qPELnTnwGJEtJexgP2qX",
name:"Runcam Cam 1",
type:"camera"
}
},
{
id:'uniqueID',
specs: {
count:1,
forSale:false,
group:"qPELnTnwGJEtJexgP2qX",
name:"Hobbywing 4 in 1",
type:"esc"
}
}
]
Here's how I'm running through these items (result being the list of items):
let partArr = [];
let typeObj = {};
result.forEach(part => {
//Put all parts in a list
partArr.push({
'id':part.id,
'specs':part.data(),
});
//Put all types in a list
typeObj[part.data().type] = {
'count': 0
};
});
Now, I need to increment the count, adding each part's count to the last depending on their type. The typeObj should look something like this.
{
esc: {
count:5
},
camera: {
count:10
}
}
I tried adding the count to the count like so:
typeObj[part.data().type] = {
'count': typeObj[part.data().type].count + part.data().count
};
but it does not recognize there being a count when I'm first making the object. (I think).
Any advice?
You can use Array#reduce to accomplish this since you want to transform an array into a single object:
const array = [
{
id: 'uniqueID',
specs: {
count: 5,
forSale: false,
group: "qPELnTnwGJEtJexgP2qX",
name: "Foxeer Cam 2",
type: "camera"
}
},
{
id: 'uniqueID',
specs: {
count: 4,
forSale: false,
group: "qPELnTnwGJEtJexgP2qX",
name: "Furibee 40a",
type: "esc"
}
},
{
id: 'uniqueID',
specs: {
count: 4,
forSale: false,
group: "qPELnTnwGJEtJexgP2qX",
name: "Runcam Cam 1",
type: "camera"
}
},
{
id: 'uniqueID',
specs: {
count: 1,
forSale: false,
group: "qPELnTnwGJEtJexgP2qX",
name: "Hobbywing 4 in 1",
type: "esc"
}
}
];
const typeObj = array.reduce((obj, { specs: { count, type } }) => {
obj[type] = obj[type] || { count: 0 };
obj[type].count += count;
return obj;
}, {});
console.log(typeObj);
What this does is assign obj[type] to either itself or if it doesn't yet exist, a new object { count: 0 }. Then it increments the count property of obj[type] by the specified count in the data.
If you have a data method that returns an object with the data (as you seem to have in the question), you can modify it like so:
const typeObj = array.reduce((obj, item) => {
const { type, count } = item.data().specs;
obj[type] = obj[type] || { count: 0 };
obj[type].count += count;
return obj;
}, {});
console.log(typeObj);
It would probably be easier to use reduce to generate the object with the counts all at once, and to call .data() only once on each iteration:
const results = [
{
data() { return { specs: {
count:5,
forSale:false,
group:"qPELnTnwGJEtJexgP2qX",
name:"Foxeer Cam 2",
type:"camera"
}}}},
{
data() { return { specs: {
count:4,
forSale:false,
group:"qPELnTnwGJEtJexgP2qX",
name:"Furibee 40a",
type:"esc"
}}}},
{
data() { return { specs: {
count:4,
forSale:false,
group:"qPELnTnwGJEtJexgP2qX",
name:"Runcam Cam 1",
type:"camera"
}}}},
{
data() { return { specs: {
count:1,
forSale:false,
group:"qPELnTnwGJEtJexgP2qX",
name:"Hobbywing 4 in 1",
type:"esc"
}}}}
];
const typeObj = results.reduce((a, item) => {
const { count, type } = item.data().specs;
if (!a[type]) a[type] = { count: 0 };
a[type].count += count;
return a;
}, {});
console.log(typeObj);
So for example I have object like this:
{
data: [
{
id: 13,
name: "id13"
},
{
id: 21,
name: "id21"
}
],
included: [
{
id: "13",
badge: true
},
{
id: "21",
badge: false
}
]
}
And now I need to loop over included and push included to data where id is equal.
So after transformation it would have badge in data, for example like this:
{
data: [
{
id: "13",
name: "id13",
included: {
id: "13",
badge: true
},
},
{
id: "21",
name: "id21",
included: {
id: "21",
badge: false
}
}
]
}
of course I tried on my own and I've created this code:
for(let i=0; i<includedLength; i++) {
console.log(a.included[i].id);
for(n=0; n<dataLength; n++) {
console.log(a.data[n]);
if(a.icluded[i].id === a.data[i].id) {
console.log('We have match!!!');
}
}
}
but it doesn't work I have an error in console
Uncaught TypeError: Cannot read property '0' of undefined
This is demo of my code.
All solutions here have gone in the same path as you had, which is not efficient. So I am posting my solution, which is more efficient than the other solutions so far. Read the code comments to understand the optimizations done.
// Convert data array into a map (This is a O(n) operation)
// This will give O(1) performance when adding items.
let dataMap = a.data.reduce((map, item) => {
map[item.id] = item;
return map;
}, {});
// Now we map items from included array into the dataMap object
// This operation is O(n). In other solutions, this step is O(n^2)
a.included.forEach(item => {
dataMap[item.id].included = item;
});
// Now we map through the original data array (to maintain the original order)
// This is also O(n)
let finalResult = {
data: a.data.map(({id}) => {
return dataMap[id];
})
};
console.log(JSON.stringify(finalResult))
Here is my solution, this will provide the required output!
It constains the same standard for loops.
Some points I would like to highlight are,
The id in included property is string, so you can use the + operator to convert it to number.
The Object.assign() method is used so that we create a new copy of the corresponding object. Read more here
var data = {
data: [{
id: 13,
name: "id13"
},
{
id: 21,
name: "id21"
}
],
included: [{
id: "13",
badge: true
},
{
id: "21",
badge: false
}
]
}
var output = {
data: data.data
};
for (var q of data.included) {
for (var j of output.data) {
if (+q.id === j.id) {
j['included'] = Object.assign({}, j);;
}
}
}
console.log(output);
.as-console {
height: 100%;
}
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
It seems like a waste of space to push the whole "included" element into the first array when a match is found (you really need that extra id element in there?) - so this just makes output like
[{id: 1, name: 'name', badge: true},{...}]
If no matching badge element is found, it sets badge to false.
var notJSON = {
data: [
{
id: 13,
name: "id13"
},
{
id: 21,
name: "id21"
}
],
included: [
{
id: "13",
badge: true
},
{
id: "21",
badge: false
}
]
};
var badged = notJSON.data.map(function (el, i) {
el.badge = notJSON.included.find(function (inc) {
return inc.id == el.id;
}).badge || false;
return el;
});
console.log(badged);
Its not a JSON, its an Object. A valid json consists of both its key and value as string. What you are trying to do is manipulate an object. The following code should help in getting the desired output.
const obj ={
data: [
{
id: 13,
name: "id13"
},
{
id: 21,
name: "id21"
}
],
included: [
{
id: "13",
badge: true
},
{
id: "21",
badge: false
}
]
}
for (var i=0; i<obj.data.length;i++){
for(var j=0; j< obj.included.length;j++){
if(obj.data[i].id == obj.included[j].id){
obj.data[i].included={
id: obj.included[j].id,
badge: obj.included[j].badge
}
}
}
}
delete obj.included
console.log(obj)
What I am doing her is:
Checking if id of obj.data is equal to that of obj.included
If they are equal add a new key called "included" in obj[data]
When the loop is over delete the "included" key from obj as its not required anymore.
var obj = {
data: [
{
id: 13,
name: "id13"
},
{
id: 21,
name: "id21"
}
],
included: [
{
id: "13",
badge: true
},
{
id: "21",
badge: false
}
]
};
obj.included.forEach((item) => {
obj.data.forEach(item1 => {
if(item.id == item1.id){
item1.included = item;
}
});
});
delete obj.included;