fnFilter with multiple values? - javascript

I got a table with a column called: "Etiquetas" , there i have multiple tag separated by comma (Ex:"Tag, Tag01, Tag02")
And i have a tag search, where i put all tags,and when you click it, this will be added to the actual search (using fnFilter), the values are passed like: '"Tag", "Tag01"' , but if i filter "Tag" , the filter shows me all rows with that word, instead of the one with the exact word. EX: Show rows with "Tag", and "tag", and "Tag01", etc.
I need help for make exact filter, and with multiples values.
I add a picture to explain this better (i'm bad at explaining things sorry)
Image with the actual problem

You can leverage find and filter for this. While this wont give you a ranked list, like for example items with most tags matched, it will show only items that have at least a matching tag.
This assumes the tags are given as an array, and that etiquettes is.a string of comma separated tags (it could also be an array, but from what I understood, you mentioned separated by comma, so I assume it's a string).
var items = [
{title: "1", etiquettes: "tag01"},
{title: "2", etiquettes: "tag,test"}
];
var tags = ["tag"];
var results = items.filter((item) => {
// splits the tags in the etiquettes, and tries to find at least a matching one. if so, find will return true to the filter function for the current item
return item.etiquettes.split(",").find((itemTag) => {
return tags.indexOf(itemTag) >= 0;
});
});
console.log(results);

Related

How do I see if a character exists within each instance of the array as I type within an array of objects?

I've been struggling with this issue so I thought I'd come here to find the fix. I'm trying to filter my objects that are in an array to only show the ones that have for example "h" in them.
This is how my array of objects is being constructed:
Object.keys(data.jello).forEach(function (id, SomeSearchValue) {
var jello = data.jello[id];
array.push({
id: jello.id,
name: jello.name,
type: 'foo',
});
}
For example, let's say my array consists of this for names.
array[blue, red, green, apple, abigail, alien]
So, I have an array of objects. In a search bar I type "a" and my array results are then all objects that have a letter 'a' in the name. so...
array[abigail, alien]
Then i type a "b" so my search is now "ab" and my array is ...
array[abigail]
So what would my code to implement this using jQuery?
The part I'm stuck on most is the actual searching as the user types without using ajax.
I'm using jQuery. Ive tried things like jQuery.grep(), inArray() but cant seem to search includes. I've also tried array.includes(). Thanks for the help!
Use Array#filter().
jQuery $.grep() is basically the same thing but also works on jQuery objects.
Following assumes you only want to search within name property and will accept the term found in any part of the name rather than just at beginning
const data = [{name:'blue'}, {name:'red'}, {name:'green'}, {name:'apple'}, {name:'abigail'}, {name:'alien'}];
const term ='ab';
const filtered = data.filter(({name}) => name.toLowerCase().includes(term.toLowerCase()))
// or use startsWith() to only match beginning of string
console.log(filtered)

jQuery SheepIt demo indexes are wrong using nested forms

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

How to get an unflattened array of multiselect values and single inputs together?

I have some dynamically created filters on a web app's page where the filter "entry" is at times the combination of a few different inputs and the values for the collection are gathered into an array to send back to the server. If these were all just single inputs then an array of values would be easy to map over to the inputs on the backend, however when one or more is a multiselect with multiple options, a flattened array of values mixing the multiselect's values and the individual input values isn't appropriate.
As an example: if I have two inputs for a given filter on a search control page, one being a multiselect and another being a text input, I would like to gather an array of two elements, the first being an array of selected values and the second as the value entered in the text input. So if in the first multiselect I select "A", "B" and the text input I enter "Joe" and the code below gathers the input values:
Coffeescript:
filters = []
$(#customFilterElements.selector).each ->
filterName = $(#).find('.filter_entry .filter_name:input').val()
filterValues = $(#).find('.filter_entry .filter_value:input').map(->
if $(#).data('multiselect')
$(#).find('option:selected').map(->
$(#).val()
).get()
else
$(#).val()
).get()
filters.push({name: filterName, value: filterValues})
Javascript: (converted from above)
var filters = [];
$(this.customFilterElements.selector).each(function() {
var filterName, filterValues;
filterName = $(this).find('.filter_entry .filter_name:input').val();
filterValues = $(this).find('.filter_entry .filter_value:input').map(function() {
if ($(this).data('multiselect')) {
return $(this).find('option:selected').map(function() {
return $(this).val();
}).get();
} else {
return $(this).val();
}
}).get();
return filters.push({
name: filterName,
value: filterValues
});
});
Current result for filterValues: ["A","B","Joe"]
The above code ends up producing an array ["A","B","Joe"] for filterValues.
I think this may be because the .get() is converting everything to a flattened array. I tried using $.makeArray() instead of .get() and I get the same results but perhaps I missed something.
Desired result for filterValues: [["A","B"],"Joe"]
What I am hoping to produce is [["A","B"],"Joe"] so it is clear that the first element (in this example) is a collection of selected values from a multiselect to the backend.
How can I adjust the above code to get the desired result (for any combination or ordering of multiselects and single inputs together) in a fairly elegant manner?
The code is intended to be applied to any dynamically created filter, so reusable instead of hardcoding to each filter.
Ok, after a full night's rest the answer came to me right away and it seems so obvious now - just need to wrap the multiselect in an array bracket after the .get()! - doh. Sometimes documenting the problem here forces a solution to bubble up or highlight what I was missing.
filters = []
$(#customFilterElements.selector).each ->
filterName = $(#).find('.filter_entry .filter_name:input').val()
filterValues = $(#).find('.filter_entry .filter_value:input').map(->
if $(#).data('multiselect')
[$(#).find('option:selected').map(->
$(#).val()
).get()]
else
$(#).val()
).get()
filters.push({name: filterName, value: filterValues})

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.

Taffydb dynamic like 'and' query

I recently started working with taffydb. Assuming I have this as my data
db= TAFFY([
{OrderNo:'prod1',range: 3,description:'one two'},
{OrderNo:'prod2',range: 2,description:'one two three'},
{OrderNo:'prod3',range: 2,description:'one three two'},
{OrderNo:'prod4',range: 6,description:'one two four three'},
{OrderNo:'prod5',range: 5,description:'three'},...
if I wanted to write a query to find all records with "one two" and "three" I'd do something like
db({description:{likenocase:"one two"}},{description:{likenocase:"three"}}).get()
this would return products 2 and 4. Unfortunately I can't figure out how to do this with a dynamic query that will have an unknown number of variables to search for. I'm doing this to let the user search for their own supplied words.
Anyone got any ideas?
As a precursor, this will not be the best answer to your problem. But it will work. :)
So the user will have the option of searching a database with an "unknown number of variables". Let's add a maximum amount of variables--perhaps 10?
Now we catch all the user's search variables in an array:
// Create a dynamic array
var userSearchVars = [];
// Fill the array from 10 HTML input type=text fields
// You can fill your array however you fancy. This is just one example!
$("#myForm input[type=text]").each(function() {
userSearchVars.push( $(this).val());
}
// Note: by default an empty input will return the empty string: ""
Using your code snippet, just query the database with the array:
db(
{description:{likenocase:userSearchVars[0]}},
{description:{likenocase:userSearchVars[1]}},
{description:{likenocase:userSearchVars[2]}},
{description:{likenocase:userSearchVars[3]}},
{description:{likenocase:userSearchVars[4]}},
{description:{likenocase:userSearchVars[5]}},
{description:{likenocase:userSearchVars[6]}},
{description:{likenocase:userSearchVars[7]}},
{description:{likenocase:userSearchVars[8]}},
{description:{likenocase:userSearchVars[9]}}
).get()
Adapting #Jacob-IT's answer so that its dynamic. Used Taffy for the first time tonight and just discovered you can pass an array of objects as the query argument.
// Create a dynamic array
var userSearchVars = [];
// Fill the array from 10 HTML input type=text fields
// You can fill your array however you fancy. This is just one example!
$("#myForm input[type=text]").each(function() {
// This is my edit - push the whole query on to the array.
userSearchVars.push({description:{likenocase: $(this).val() }});
}
// Then pass the whole query array in...
db( userSearchVars ).get()
Tested the above - and it worked for me.
You can do it like this
let items = [];
items.push({description:{likenocase:"one two"}});
items.push({description:{likenocase:"three"}});
db(...items).get()

Categories

Resources