jQuery SheepIt demo indexes are wrong using nested forms - javascript

I am using the demo here: http://www.mdelrosso.com/sheepit/index.php?lng=en_GB&sec=demo3
But if you have two of the outer forms (addresses) and two each for the inner forms (numbers) and inspect the elements you'll notice the names of the inputs still have the #index# and/or #index_phone# strings in the index names.
If you try to submit the form then, the field data is lost (since only the latest copy of that name is kept). I've tried debugging the JavaScript so I can patch it, but I'm not seeing where it's wrong. It seems like the normalizeForms function isn't handling nesting correctly.
What can I do to correct the code so the indexes perform as expected? (That is: so that an input of two addresses (A and B), each with two phone numbers (A1, A2 and B1, B2) gives me a POSTed value like:
"people" : [
0 : {
"addresses" : "A",
"phones" [ 0 : "A1", 1: "A2" ]
},
1 : {
"addresses" : "B",
"phones" [ 0 : "B1", 1: "B2" ]
}
]
(Note: I'm not looking for that exact format; I can parse any output, I just need to get all of the data from the client to the server with meaningful indexes and without conflicts.)

There appear to be some fundamental logic issues with the index 'normalization' side of this plugin when it comes to the nested inputs.
Essentially there is is a nametemplate and an idtemplate which are the element names only with %index% or %index_phones% where the index should be, and then the name and id which should be these templates only with the %index% or %index_phones% replaced with the actual element input ids.
What happens during the 'normalization' process is that a function runs over these templates (once per element per form), and depending on the form, replaces either %index% or %index_phones% with the relevant index, depending on which form is being processed.
The problem arises when the inputs are nested, as the function first replaces (for instance) %index% with let's say 0. It then updates the resulting name or id with this value, say person_addresses_0_phones_%index_phones%_phone. When it hits the nested form, it then does the same again, only with %index_phones%. The result is now person_addresses_%index%_phones_0_phone because it is still using the unmodified template attribute, rather than the already half-modified name.
To fix this properly, the logic around this whole section of the plugin really needs rebuilding, but I have slapped together a quick patch which should serve as a temporary fix.
In the main plugin file, update the normalizeFieldsForForm function to be:
function normalizeFieldsForForm(form, index)
{
form.find(formFields).each(function(){
var that = $(this)
,idTemplateAttr = getOrSetTemplate(that,"id")
,nameTemplateAttr = getOrSetTemplate(that, "name")
,idAttr = that.attr("id")
,nameAttr = that.attr("name")
,formParents = that.parents('[idtemplate]')
/* Normalize field name attributes */
var newNameAttr = nameTemplateAttr.replace(options.indexFormat, index);
/* Normalize field id attributes */
var newIdAttr = idTemplateAttr.replace(options.indexFormat, index);
$.each(formParents,function(index,element){
$element = $(element);
if($element.data('indexFormat') != options.indexFormat){
/* Normalize field name attributes */
newNameAttr = newNameAttr.replace($element.data('indexFormat'), $element.data('formIndex'))
/* Normalize field id attributes */
newIdAttr = newIdAttr.replace($element.data('indexFormat'), $element.data('formIndex'))
}
});
form.find("label[for='"+idAttr+"']").each(function(){
$(this).attr("for", newIdAttr);
});
that.attr("id", newIdAttr);
that.attr("name", newNameAttr);
});
}
And then update the addForm function. Around line 385 in an unmodified plugin file, add the line
// Index format
newForm.data('indexFormat', options.indexFormat);
above the line
// Index
newForm.data('formIndex', getIndex());
This should serve as a fix until the plugin author gets around to fixing the logic issues. This is for plugin version 1.1.1

Related

How to check if array index is not equal to argument?

Still learning Javascript by creating mini text RPG games via HTML pages :)
Good practice, trying to learn some new way or add some new better codes into my project.
Right now I'm trying to add language to my project via function;
language.addLang = function(name,id){
if (id != this.log[id]) {
this[name] = new Object;
this.log[id] = name
}
}
Edit;
Was trying to say if you can compare array index number to argument id number.
The name on the argument is just a language name, like English with a string value.
And id is just what array index it will be placed into. And also a conditional branch that will translate all text into that language for later use.
for people that wonder what log is;
language.log = [
undefined, 'English','Swedish','Japanese','German'
]
Summary;
As above, log array length is right now 5.
So let's say I want to add a new language to my project that I will translate, later on, I can then write language.addLang('Chinese',5).
That will add 'Chinese' string into array index number 5.
However! If I would add from a different index number that already exists it will show some error instead of overwriting 'Chinese' to another language.
I hope this explains better than my last post.
I can translate it manually instead of adding a new object for each language.
But would be life-saving if I can compare argument number to index number.
#Charliefl is right but I guess this may give you a clue to apply to your case by modifying according to your other code.
var IncludedLanguages = [ 3 , 4 , 5 ]
var LangObjectsArray = []
language.addLang = function(name,id){
if ( IncludedLanuages.includes( id ) != true ) {
var obj = { "name" : name , "id" : id }
LangObjectsArray.push( obj )
IncludedLanguages.push( id )
}
}

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.

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

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.

Searching a key in javascript object

I have a building a chrome extension, I have following data as
var data = {}
data["Five, ok"] = "another one"
chrome.storage.sync.set(data)
chrome.storage.sync.get(function(content){console.log(content)})
>> {'Five, ok': "Another one ", 'ok, done': "New one"}
This can grow bigger with many values. (Key is a comma separated value).
I want to get all keys which include (2 different cases, this are user give values)
1. ok
2. done
this values are dynamic, what is the best way to achieve this in JavaScript/ jquery
chrome.storage.sync.get(function(content) {
var keys = Object.keys(content);
var keysOK = keys.filter(function(key){ return key.search(/\b(ok|done)\b/i) });
console.log(keysOK);
});
/\b(ok|done)\b/i finds the keys containing either ok or done
/\bok\b/i finds the keys containing ok
/\bdone\b/i finds the keys containing done
The i at the end makes the search case-insensitive.
As #charlietfl commented it's not efficient. However chrome.sync doesn't allow more than 100kB of data anyway so it's probably not an issue.

How do I scan JSON with jquery to determine the number of instances of a certain string?

I have some JSON which looks generally like this...
{"appJSON": [
{
"title":"Application Title",
"category":"Business",
"industry":"Retail",
"language":"English",
"tags":[
{"tags":"Sales"},{"tags":"Reporting"},{"tags":"Transportation"},{"tags":"Hospitality"}
],
},
{
"title":"Airline Quality Assurance",
...
...
...]}
I'm looping through JSON to get an array of all of the unique Tags in the data.
My question is, now that I have an array of the different unique Tags in the JSON, how do I best determine the number of times each Tag occurs?
So basically I'm looking to generate a list of all of the tags found in the JSON (which I already have) with the number of times each one occurs (which I don't already have).
Thanks a lot in advance!
I'm assuming when you find a new tag you check to see if you already have that tag somewhere. If you don't you add it to your list. Why not when you check do something like.
var nextTag=//get the next tag in the JSON list
var newTag=true;
for(var i=0;i<tags.length;i++){
if(nextTag === tags[i]){
tagCount[i]++;
newTag=false;
break;
}
}
if(newTag){
tags[tags.length]=nextTag;
tagCount[tagCount.length]=1;
}
This uses two arrays where tagCount[i] is the number of times tag in tags[i] occurs. You could uses an object to do this or however you wanted to.
As an alternative, here's a function which will fill an associative array; the keys will be the tags and the values will be the number of occurrences of that tag.
var tagCounts = []; // Global variable here, but could be an object property or any array you like really
function countTags(tags, tagCounts)
{
$.each(tags, function(i, item) {
var tag = item.tags; // This would change depending on the format of your JSON
if(tagCounts[tag] == undefined) // If there's not an index for this tag
tagCounts[tag] = 0;
tagCounts[tag]++;
});
}
So you can call this function on any number of arrays of tags, passing in your tagCounts (totals) array, and it will aggregate the totals.
var tags1 = [{"tags":"Sales"},{"tags":"Reporting"},{"tags":"Transportation"},{"tags":"Hospitality"}];
var tags2 = [{"tags":"Reporting"},{"tags":"Transportation"}];
var tags3 = [{"tags":"Reporting"},{"tags":"Hospitality"}];
countTags(tags1, tagCounts);
countTags(tags2, tagCounts);
countTags(tags3, tagCounts);
Then you can read them out like so:
for(var t in tagCounts)
// t will be the tag, tagCounts[t] will be the number of occurrences
Working example here: http://jsfiddle.net/UVUrJ/1/
qw3n's answer is actually a more efficient way of doing things, as you're only looping through all the tags onceā€”but unless you have a really huge JSON source the difference isn't going to be noticeable.

Categories

Resources