There is an object containing objects having this form:
bigObject: {
"a - values": { atr: true}
"a - items": { atr: true}
"a - others": { atr: false}
"b - values": { atr: true}
"b - items": { atr: true}
"b - others": { atr: false}
"c - values": { atr: false}
"c - items": { atr: true}
"c - others": { atr: false}
}
I use this object inside a function to check every time one of the attributes had changed its boolean value: onButtonClicked(item)
it does something like:
onButtonClicked(item) {
bigObject[item.id].atr= !bigObject[item.id].atr;
}
Inside this function, I want to split them in order to be able to check the values for objects starting with a, b and c separately. For that I did: const toCheck = item.id.split("-")[0];
this works fine, it will take only the objects starting with a if that one was clicked.
the next step is to check if there are both true and false attributes for a specific letter.
For this I tried to do it like:
let countFalse = 0;
let countTrue = 0;
bigObject.forEach(x => {
if ((x.split("-")[0]) === toCheck) {
if (x.atr) {
countTrue++;
} else countFalse++;
}
if (countTrue && countFalse) {
console.log("has both true and false attributes");
} else console.log("nope");
});
So I'm splitting the original name to get rid of (values, items, others) and after that I try to count the true and false attributes. If there are both of them, show a message telling that otherwise, no.
Something is wrong but I don't understand what. Any ideas?
4 Answers 4
You could iterate the entries with splitting by ' - ' instead of '-'.
var bigObject = { "a - values": { atr: true }, "a - items": { atr: true }, "a - others": { atr: false }, "b - values": { atr: true }, "b - items": { atr: true }, "b - others": { atr: false }, "c - values": { atr: false }, "c - items": { atr: true }, "c - others": { atr: false } },
countFalse = 0,
countTrue = 0,
toCheck = 'a';
Object.entries(bigObject).forEach(([k, v]) => {
if (k.split(" - ")[0] !== toCheck) {
return;
}
if (v.atr) {
countTrue++;
} else {
countFalse++;
}
});
if (countTrue && countFalse) {
console.log("has both true and false attributes");
} else {
console.log("nope");
}
A more compact version with an object for counting.
var object = { "a - values": { atr: true }, "a - items": { atr: true }, "a - others": { atr: false }, "b - values": { atr: true }, "b - items": { atr: true }, "b - others": { atr: false }, "c - values": { atr: false }, "c - items": { atr: true }, "c - others": { atr: false } },
count = { false: 0, true: 0 },
toCheck = 'a';
Object.entries(object).forEach(([k, { atr }]) => count[atr] += k.startsWith(toCheck));
if (count.true && count.false) {
console.log("has both true and false attributes");
} else {
console.log("nope");
}
console.log(count);
2 Comments
let. => ES6As I know, forEach does not iterate over objects. I suggest you use
const bigObjectKeys = Object.keys(bigObject)
than iterate like this:
bigObjectKeys.forEach(element => { bigObject[element] ...})
Or use lodash forEach, it can iterate over objects.
Comments
Things you got wrong and to be fixed :
- Iterate through the
keys/entriesof an object. - Split with
-, not with-. - Check using
if, only after you have completed iterating through all elements.
var countFalse = 0;
var countTrue = 0;
var bigObject= {
"a - values": { atr: true},
"a - items": { atr: true},
"a - others": { atr: false},
"b - values": { atr: true},
"b - items": { atr: true},
"b - others": { atr: false},
"c - values": { atr: false},
"c - items": { atr: true},
"c - others": { atr: false}
}
var toCheck = "a";
Object.keys(bigObject).forEach(x => {
if ((x.split(" - ")[0]) === toCheck) {
if (bigObject[x].atr) {
countTrue++;
} else countFalse++;
}
});
if (countTrue && countFalse) {
console.log("has both true and false attributes");
} else console.log("nope");
To be more efficient,
var countFalse = 0, countTrue = 0;
var bigObject= {
"a - values": { atr: true},
"a - items": { atr: false},
"a - others": { atr: false},
"b - values": { atr: true},
"b - items": { atr: true},
"b - others": { atr: false},
"c - values": { atr: false},
"c - items": { atr: true},
"c - others": { atr: false}
}
var toCheck = "a";
Object.keys(bigObject).forEach(x => {
if ((x.split(" - ")[0] === toCheck) && !(countTrue>0 && countFalse>0))
{
bigObject[x].atr ? countTrue++ : countFalse++;
}
});
if (countTrue && countFalse) {
console.log("has both true and false attributes");
} else console.log("nope");
Comments
Could use Array#filter and Array#every on the Object entries
const isMatching = (str) =>{
const arr = Object.entries(bigObject).filter(e=> e[0].startsWith(str));
// makes sure every entry has same `atr` as the first entry
return arr.every(e => e[1].atr === arr[0][1].atr);
}
['a','b','c'].forEach(s => console.log(s, isMatching(s)))
<script>
const bigObject= {
"a - values": { atr: true},
"a - items": { atr: true},
"a - others": { atr: false},
"b - values": { atr: true},
"b - items": { atr: true},
"b - others": { atr: false},
"c - values": { atr: false},
"c - items": { atr: false},
"c - others": { atr: false}
}
</script>
Comments
Explore related questions
See similar questions with these tags.
forEachfrom?bigObject.forEach is not a functionforEachis for arrays not object literals