Dynamically comparing multidimentional array key/values against multiple data attribute/values - javascript

I have multiple selects set up as filters to filter (hide/show) DOM elements within a specific section of the page. The sections are set up like this (simplified):
<section id="people">
<div data-filtervals="{"titleLevel":["2"],"titleFunction":["4","13"]}">John Doe</div>
.
.
.
<div data-filtervals="{"titleLevel":["1"],"titleFunction":["2","3","10"]}">Sally Smith</div>
</section>
My filters produce an array like this in console.log(filter):
titleFunction: Array[2]
0: "1"
1: "2"
length: 2
titleLevel: Array[3]
0: "1"
1: "2"
2: "3"
length: 3
I am trying to write a function that will iterate over .each of the #people > div's and if the data-key(s) are not in the filter[key] value(s), hide the divs.
So in the example above, John Doe would be hidden because his data-titleLevel AND data-titleFunction are not included in the filter array. There are overlaps in data attribute values so combining them into a single array is not possible and legacy code prevents me from altering this for the moment.
My challenge is more about creating a Javascript (or jQuery) function that can dynamically compare one or more filters against data attributes with matching keys. I have been able to get the filter to work for either/or but not to dynamically filter against multiple filters, unless I hard code it.
I looked into .some() but keep hitting a wall with the logic and other SO "Array in Array" solutions like this and this but I have found they don't seem to quite solve this challenge.
EDIT:
I have decided to combine the data attributes into a single data attribute with the value being JSON with keys matching the filter keys; perhaps this will make the comparison easier. Still looking for a solution while I work on it.

Well here's my attempt at this.
I don't know where your filters are coming from but if they're dynamic I hope they are in an one object. With that hypothesis I made a solution.I'm also guessing that you have found a way to organize the divs into one array of objects
So assumming that
var filters = {titleLevel:[1,2],titleFunction:[1,2,3]};
var divs = [{titleLevel:[2],titleFunction:[4,13]},{titleLevel:[1],titleFunction:[2,3,10]}];
var hasOverLap = function(arr1,arr2){
var flag = false;
arr1.forEach((item)=>{
if(arr2.indexOf(item) != -1){flag = true;}
});
return flag;
};
The following code should get you an object of filtered divs
divs.filter(div=>{
for(var key in div){
if(!hasOverLap(div[key],filters[key])){
return false;
}
}
return true;
});
It's not a complete solution but i hope it helps you get started.

Related

What is the best way to itterate over key value pairs nested in an index using javascript?

I am trying to sort sets of associated key value pairs. They look like this:
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
But organized into labeled subsets of preferably a string or perhaps an index if necessary.
The data-set is a vote-per-use table of most used english words being parsed into pages.
I will be appending them as text to other html elements due to the constraints my use case, makes it a bit tricky, however, for an example I could work with a simple console.log of the page value followed by the console.log of every word value stored within that page. I need the order preserved. so probably indexed. I will also need to be able to sort each page by the votes value, but I think I can figure the rest out for that.
I have found tutorials on how to search through key-value pairs, but I cannot find how to do all of the following with one solution:
A: access the value of word
B: maintain the order of the data-set, allowing me to append them to the matching html element
C: allows me the opportunity to change which set of elements I am appending to when i have finished looping through a single member of the parent index (the one recording the page)
I imagine it is some combination of for/of and for/in, but I'm getting a headache. Please help?
addl info:
function would run at app startup or when the dataset being examined is changed.
function would take a large dataset filled with around 200 page number values, each with 60+ sets of data like the one listed above, the contents of a single page index for example:
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aaron","votes":4129,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abandoned","votes":1289,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abc","votes":5449,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aberdeen","votes":641,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abilities","votes":2210,"userMade":"FALSE","limiter":"FALSE"},
{"word":"ability","votes":7838,"userMade":"FALSE","limiter":"FALSE"},
{"word":"able","votes":8649,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aboriginal","votes":1837,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abortion","votes":3232,"userMade":"FALSE","limiter":"FALSE"},
{"word":"about","votes":9295,"userMade":"FALSE","limiter":"FALSE"},
{"word":"above","votes":8818,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abraham","votes":867,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abroad","votes":4969,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abs","votes":2415,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absence","votes":4934,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absent","votes":2937,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absolute","votes":5251,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absolutely","votes":5936,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absorption","votes":285,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abstract","votes":7946,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abstracts","votes":1907,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abuse","votes":7238,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academic","votes":7917,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academics","votes":1706,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academy","votes":6755,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acc","votes":6469,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accent","votes":1020,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accept","votes":7547,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acceptable","votes":4907,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acceptance","votes":7273,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepted","votes":7684,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepting","votes":1789,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepts","votes":1535,"userMade":"FALSE","limiter":"FALSE"},
{"word":"access","votes":9031,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessed","votes":2932,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessibility","votes":5702,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessible","votes":5662,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessing","votes":2096,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessories","votes":8875,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessory","votes":5661,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accident","votes":5664,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accidents","votes":2991,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodate","votes":1807,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodation","votes":8059,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodations","votes":3885,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accompanied","votes":2532,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accompanying","votes":664,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accomplish","votes":1070,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accomplished","votes":2419,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accordance","votes":6434,"userMade":"FALSE","limiter":"FALSE"},
{"word":"according","votes":8282,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accordingly","votes":3003,"userMade":"FALSE","limiter":"FALSE"},
{"word":"account","votes":8996,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accountability","votes":3029,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accounting","votes":7459,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accounts","votes":7507,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accreditation","votes":1605,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accredited","votes":3027,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accuracy","votes":6779,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accurate","votes":6427,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accurately","votes":1493,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accused","votes":2853,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acdbentity","votes":1389,"userMade":"FALSE","limiter":"FALSE"},
and the output would ultimately append the value paired with each word to a specific button through iteration, but also sorted by the page value.
each page is a set of buttons in a 3d object that looks like this:
the text is appended to each button which in turn is a 3d object embeded in an html object using aframe. I can make the appending code.
You can use Object.entries() to get the key value pairs of an object.
var words = [
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aaron","votes":4129,"userMade":"FALSE","limiter":"FALSE"}
];
words.forEach((wordEntry) => {
var keyValuePairs = Object.entries(wordEntry);
keyValuePairs.forEach((kv) => {
console.log(`key: ${kv[0]} value: ${kv[1]}`);
});
});
my latest attempt looks like this:
for (let p=1; p<129; p++){
for (let b=1; b<68; b++){
let pTpl = (p).toLocaleString(undefined, {minimumIntegerDigits: 3});
let bDbl = (b).toLocaleString(undefined, {minimumIntegerDigits: 2});
var `#fCont${pTpl}${bDbl}` = document.createElement('a-text');
`fCont${pTpl}${bDbl}`.setAttribute('value', 'engWordLib[p,b,0]');
`fCont${pTpl}${bDbl}`.setAttribute('votes', 'engWordLib[p,b,1]');
`fCont${pTpl}${bDbl}`.setAttribute('userMade', 'engWordLib[p,b,2]');
`fCont${pTpl}${bDbl}`.setAttribute('limiter', 'engWordLib[p,b,3]');
`fCont${pTpl}${bDbl}`.setAttribute('visible', 'false');
`fBtn${bDbl}`.appendChild(`#fCont${pTpl}${bDbl}`)
}
}
please note that I havent checked this for errors. I still think this code is to WET and I would prefer the key names for the properties be preserved in the datastructure rather than tacked on when it's appended to the page. I guess I could add a dimension to the array.... seems kind of messy when an object property value has the key value pairs right in it. cant get the iteration of objects in an array down though.... Will continue to persue a cleaner method.

Separate objects in an array from their index using localstorage

I am looking for a way to separate objects from an array, having only the index avaiable. I have something like this:
var hello= [];
for (var i=0; incr.lenght>0; i++;)
{
hello+= originalarray[incr[i]].item;
}
Array:
0: item0
1: item1
2: item2
3: item3
Having this: hello+= originalarray[incr[0,2,3]].item;
I get this: item0item2item3
The "item" comes from another array, this is a small part of my code, but hopefully it's enough to explain my problem.
When I create an alert(hello); what I get is a list of item like this: item0item1item2item3. What I am looking for is a way to separate them. But I need to use the localStorage as well, and I was thinking of creating a different key for every value of the index. Hope it makes sense, I am a new user. Thank you very much!
First of all, the for loop you have in your question has several issues:
It has three ;, while the syntax only allows two. You need to remove the final one
It has a condition that is never true, because lenght has a spelling mistake. If you correct it it will always be true (infinite loop):
incr.length>0
This should be:
i < incr.length
Then the main issue is that you apply a string operator (+=) to concatenate the items, and so hello is no longer an array, but a string:
hello+= originalarray[incr[i]].item;
Instead you should use push:
hello.push(originalarray[incr[i]].item);
In order to store hello in localStorage you should not try to make a key for each item and store each separately. Instead use JSON.stringify (for writing) and JSON.parse (for reading) as explained in this Q&A.

How do I sort a table with Javascript in alphabetical order with case sensitivity?

No jQuery answers as I don't use it in this site.
I have a table in the general form
<tbody><tr><td>2</td><td>Ah! My Goddess</td></tr></tbody>
I need to access the inner text of the 'a' element, and I'm not sure how to do this. I wanted to use querySelectorAll but apparently, because the table is generated by javascript through ajax, I cannot do this. This leads me unsure of how to get to the a element let alone sort its text content, such as 'Ah! My Goddess'. The caveat is there are many more table rows like this, with the same basic pattern.
Without using jQuery you could try and use the root of the functions that it is based on. Such as for replacing the selectors with:
document.querySelectorAll('td').textContent
I'm assuming you can refer to the table by id:
var t = document.getElementById(/*table id*/);
var d = t.tBodies[0].rows; // is an HTMLCollection, kinda like an array
d = [...t.tBodies[0].rows]; // converts it into an array of rows
once it's in an array, you can do array-like things to the rows, like sort() them
now, looking at the first row d[0] and assuming that the anchor is always in the second column, the anchor can be referred to as:
var a = d[0].cells[1].getElementsByTagName('a')[0];
and the text inside the opening/closing tags is:
a.innerHTML; // In this case: 'Ah! My Goddess'
putting some of this together, a sort (alphabetically) could be:
var byAnchorText = (a, b) => a.cells[1].getElementsByTagName('a')[0].innerHTML - b.cells[1].getElementsByTagName('a')[0].innerHTML;
var t = document.getElementById(/*table id*/);
Array.sort.apply(t.tBodies[0].rows, byAnchorText);
or something like this, you can fix it up as you see fit.

How can I add elements to a part of a json by using jquery

I try to add elements in a particular way to the following JSON:
var data = [{"name":"google",
"ip":"10.10.10.01",
"markets":[{"name":"spain","county":"6002,6017,6018,6019,6020"},
{"name":"france","county":"6003,6005,6006,6007,6008,6025,6026,6027,6028,6029"},
{"name":"japan","county":"6004,6021,6022,6023,6024"},
{"name":"korea","county":"6000,6013,6014,6015,6016"},
{"name":"vietnam","county":"6001,6009,6010,6011,6012"}]},
{"name":"amazon",
"ip":"10.10.10.02",
"markets":[{"name":"usa","county":"10000,10001,10002,10003,10004,10005"}]},
{"name":"yahoo",
"ip":"10.10.10.03",
"markets":[{"name":"japan","county":"10000"}]}];
I want to add this element to the json:
newData = [{"name":"amazon",
"ip":"10.10.10.02",
"markets":[{"name":"mexico","county":"9000"}]}];
The result might be exactly this:
var data = [{"name":"google",
"ip":"10.10.10.01",
"markets":[{"name":"spain","county":"6002,6017,6018,6019,6020"},
{"name":"france","county":"6003,6005,6006,6007,6008,6025,6026,6027,6028,6029"},
{"name":"japan","county":"6004,6021,6022,6023,6024"},
{"name":"korea","county":"6000,6013,6014,6015,6016"},
{"name":"vietnam","county":"6001,6009,6010,6011,6012"}]},
{"name":"amazon",
"ip":"10.10.10.02",
"markets":[{"name":"usa","county":"10000,10001,10002,10003,10004,10005"},
{"name":"mexico","county":"9000"}]},
{"name":"yahoo",
"ip":"10.10.10.03",
"markets":[{"name":"japan","county":"10000"}]}];
I tried to use :
$.extend(data.markets, newData)
$.extend(true, data, newData); //this works only in the case every element is new.
but nothing works the way I pretend.
Could anyone give me a solution?
Thanks in advance.
You haven't created JSON, you've created a JavaScript literal object.
You could add this particular piece of newdata by
data[1].markets.push({"name":"mexico","county":"9000"})
Because you are dealing with javascript objects, you can write a function to check for the existence of data[n] and push data.
You have an array of objects, where each object is like the following:
var item = {"name":"...",
"ip":"...",
"markets":[ /*some objects here*/];
}
So why not just creating your custom method to insert elements? It could search in the array if an item with the same name and ip exists, and then:
If it does exist: append the markets to the existing item markets attribute (maybe you need to check again if they already exist). UPDATE:The code that #jasonscript added in his answer will do the job: once you have found where to add the market, just add it to the array. Again, maybe you'll have to check if that market was already in the array. Using jQuery it will be: $.extend(true, data[i],newData)
If it doesn't exist: just add the item to the array: $.extend(true, data,newData)
Stealing a little code from another answer:
$.each(data, function(item){
if(item.name == newData[0].name && item.ip == newData[0].ip) {
item.markets.push.apply(item.markets, newData[0].markets);
}
}
This assumes that you know that all the market items in the new object are different to the existing ones - otherwise you'd have to do a nested foreach or something. If you can change the notation of the objects a little you could think about using a dictionary-like object for Markets to make that a little cleaner.
In fact, changing data from an associative array would probably work for that too. Then you could easily check for existence with:
if(data[myNewDataName]){
//add to markets
} else {
data[myNewDataName] = myNewData;
}

Joining values in an Javascript array

Say I have:
var Certificated = {}
Sub items are added dynamically and variate. Possible outcome:
var Certificated = {
Elementary: ["foo","bar", "ball"]
MiddleSchool: ["bar", "crampapydime"]
};
I want to do the following:
Certificated.Elementary = Certificated.Elementary.join("");
Except I need it to do that on all of the objects inside.
Keep in mind I can't know for sure the titles of nor how many objects will be inside Certificated.
My question is how can I use .join("") on all elements inside Certificated, without calling each one specifically?
EDIT: I am aware .join() is for arrays and the objects inside Certificated are going to be arrays. Therefore the join method.
Does this work?
for (var key in Certificated) {
if (Certificated.hasOwnProperty(key)) {
Certificated[key] = Certificated[key].join("");
}
}
It loops through all properties of Certificated, and makes a quick safe check for the key being a real property, then uses bracket notation - [""] - to do your join.
Quick question - are you sure you want to use join? I know you just provided an example, but you can't call join on a string...it's for arrays. Just wanted to make sure you knew.
Here's a jsFiddle of my code working with arrays being used for the properties:
http://jsfiddle.net/v48dL/
Notice in the browser console, the properties' values are strings because the join combined them with "".

Categories

Resources