How does the matching JS code using indexOf work? - javascript

I've managed to copy some JS over into my doc, and I've got it working. But I don't entirely understand how its doing it.
It's a search function to match with data in a table and hide any rows that don't match.
But I don't understand the active line of code that actually searches and matches. Would someone explain it?
$('#searchBar').keyup(function() {
searchFunction($(this).val());
});
function searchFunction(value) {
$('#results tr').each(function() {
var found = 'false';
$(this).each(function() {
if ($(this).text().toLowerCase().indexOf(value.toLowerCase()) >= 0) {
found = 'true';
}
});
if (found === 'true') {
$(this).show();
} else {
$(this).hide();
}
})
};
It's this line I can't get my head around:
if ($(this).text().toLowerCase().indexOf(value.toLowerCase()) >= 0) {
found = 'true';
}
I understand how it changes the variable to true, but I don't understand how it matches the data in the Table row with the Value fed in.

It converts the value you sent to the function to lowercase, and then looks at the data in the row. It converts that to lowercase too, and sees if there is a match using indexof, which is covered here: How to use IndexOf in JQuery
Basically, the indexOf() method returns the position of the first occurrence of a specified value in a string. It returns -1 if the value to search does not occur.
Consider searching for "test"
var str = "Hello this is a test";
var n = str.indexOf("test");
The result of n will be: 16, ergo, as in your script, larger than 0... and "found"

What it does is
For each rows in my table "result"
If one of all these values, that I look in lowercase, is equal to what I typed in the "searchBar" in lower case, more than one time, then I found it, and so found = "true"

From search bar key press event will be triggered and value of search bar will passed to search function
$("#searchBar").keyup(function() {
searchFunction($(this).val());
});
function searchFunction(value) {
//value will contain the value of search bar
$("#results tr").each(function() {
//assuming value is not there in tr
var found = "false";
//now searching for each tr for value
$(this).each(function() {
//converting to lower case and comparing each value with searchbar value
if (
$(this)
.text()
.toLowerCase()
.indexOf(value.toLowerCase()) >= 0
) {
found = "true";
}
});
//actual showing/hiding row
if (found === "true") {
$(this).show();
} else {
$(this).hide();
}
});
}
if need more info about index of
https://www.w3schools.com/jsref/jsref_indexof.asp
#MattCouthon let me know if you need anything else

Related

How to get a tr value within a filter

I having issues grabbing my data within a jquery filter. I have tried finding a solution but haven't been able to find one. I am fairly new with Jquery so I believe this might be a trivial answer.
I like to loop through my array checking it against the cells value, How do I fetch the cells current value / (this) value?
EDIT: Thanks for the help, final solution as follows. Where datesToSearchFor is an array of string dates and nth-child(2) is my dates column in my table.
$("#UnfinishedTable tr").filter(function () {
if (this.id !== 'headerRow') {
var isItThere = false;
var data = $(this).find("td:nth-child(2)").html();//my dates column
datesToSearchFor.forEach(function (entry) {
if (data == entry) {against are array of dates
isItThere = true;
}
});
}
if (isItThere) {//if one was found show the row else hide it
$(this).show()
}
else {
if (this.id !== 'headerRow') {
$(this).hide()
}
}
});
$('#unfinishedTable tr').not('#headerRow').each(function(){
var val = $(this).attr('value');
var src = datesToSearchFor.find(function(n){return n == val;});
$(this).css({'display' : src == null ? 'none' : ''});
});
Filtering is for finding your elements, not acting upon them. After you .filter(), you should put your logic into .each()
$('#UnfinishedTable tr')
.not('#headerRow')
.each(function () {
... // logic
$(this).show();
});
The above example uses .not() as that is closer to what your desired logic is.
The above code seems to be correct, does the console return any errors? Is datesToSearchFor a string vector? Is headerRow the id you assigned to the header tr to ignore it?

Avoid jquery function for all the content

I have a table with 20 rows. In each row there is an element
<p class="exp-date">'.$cust->Expiration_Date.'</p>
This element is going to be repeated and return different values but in a lot of rows return 0001-01-01.
I want to hide this content so I wrote this in javascript
var exp = $(".exp-date").val();
var exphide = '0001-01-01';
if(exp = exphide) {
$(".exp-date").html('');
}
and also have tried this
$('.exp-date').each(function() {
if(exp = exphide) {
$(".exp-date").html('');
}
});
But in both cases apply the jquery on the first row and modify everything not only where the statement is declared.
Someone any idea?
Thanks in advance
You're using assignment in if statement. The condition exp = exphide will always evaluate to true and the code inside the if statement will execute for all the elements.
Change
if(exp = exphide) {
to
if(exp == exphide) {
or
if(exp === exphide) {
Also, use text() instead of html() to get the date, and use trim() on it to remove extra spaces before comparing.
Use this/$(this) inside the each to get the innerText of the current element.
$('.exp-date').each(function () {
if ($(this).text().trim() == exphide) {
// ^^^^^^^^^^^^^^^^^^^^^^^^
$(this).html('');
// ^^^^
}
});
Use == and "this", else it will point to all classes. Code shown below
var exphide = '0001-01-01';
$('.exp-date').each(function() {
if(this.innerHTML == exphide) { //this.innerHTML
$(this).html(''); //this.html..else will point to all classes
}
});
First you should correct the syntax in the if condition and then try the below code. When you are using "each" for looping you should pass index and value to the callback function as shown below. Then you can achieve the desired result.
var exphide = '0001-01-01';
$('.exp-date').each(function(index, value) {
var exp = $(value).text();
if(exp == exphide) {
$(value).html('');
}
});
I suggest not to remove the content from table cell instead you can hide. Hope this helps.

Filter options by reading character length inside for loop

I have a widget (the widget code in the pen linked below is not the actual code, please just pay attention to the filtering function jQuery.fn.doFilterOptions(){..}).
Use case:
I have a non-native selectbox. I need to extend its functionality to accept an onclick event which allows the user to type data into the selectbox (not targeting a traditional <select>), it should filter the .options available by simply showing or hiding them based on its inner HTML value, if no match is found at any point during the loop through the string being entered by the user, I need the options to continue not being displayed.
Issue:
Right now it works 95% of the way, the only issue is that if an invalid char is found, the loop keeps checking the rest of the users entries char by char, and if the next char is a match to any of the options in the same index, it re-display's this as a valid .option.
$('.selectbox .selected').on('keyup', function(){
var theseOptions = $(this).parent('.selectbox').find('.option');
var defaultPlaceholder = $(this).data('placeholder');
var filterOptions = (function(curSelectedVal){
if (curSelectedVal === ' ' || curSelectedVal.length === 0 || curSelectedVal === defaultPlaceholder){
theseOptions.show();
}
var optionsVal;
var doInputOptionsComparison = (function(){
var invalidOption = false;
for (var letterPos = 0; letterPos < curSelectedVal.length; letterPos++){
theseOptions.each(function(optionIteration){
var thisOption = $(this);
thisOptionsVal = thisOption.html();
if (curSelectedVal.length > thisOptionsVal.length ){ // If a longer string has been input by the user than exists in the option being iterated over, hide this option
thisOption.hide();
invalidOption = true;
}
else if ((thisOptionsVal[letterPos].toLowerCase().trim() === curSelectedVal[letterPos].toLowerCase().trim()) && invalidOption === false){ // If the input string matches this option and no invalid options have been found in the letterPos prior to it, show this option
thisOption.show();
}
else { // If the string does not match any option
invalidOptionFound = true;
thisOption.hide();
}
});
}
})();
})($(this).html());
});
Here is the demo, try selecting then typing abz you will see the filter working properly.
Now erase that input data, and now type azc. You will see the abc option comes available again because the c matches in that same index (user input[i] = optionsHtml[i] = show();), resulting the the above described undesirable effect.
http://codepen.io/nicholasabrams/pen/KwwMPG?editors=001
BONUS:
Would this be easier by using regEx to do the filtering?
I managed to use a dynamic regEx filter function it it cut the code down big time! Wow what a better solution.
$.fn.filterOptionsByUserInput = function(optionSelector){
var curInput = $(this).html().trim().replace(/ /g, '').toLowerCase();
$(optionSelector).each(function(optionIndex){
var userInputRegEx = new RegExp('^'+curInput+'.*');
if ($(this).html().toLowerCase().trim().match(userInputRegEx)){
$(this).fadeIn('slow');
}
else {
$(this).fadeOut('slow');
}
});
};
http://codepen.io/nicholasabrams/pen/LEEwrm?editors=001

jquery filter values according to specific character at specific position

I am trying to filter a table of part numbers according to a user-defined value at a specific position.
see jsFiddle --> http://jsfiddle.net/bagofmilk/wx9F3/12/
The problem is that I'm allowing multiple conditions - not just ONE character at ONE position.
If you take a look at the fiddle you will see I use Table Sorter 2.0 Plugin which works great. But I also created a small table above that with 7 textboxes. Each of these textboxes represents a value of a part number in the table below.
'data-log' = if the textbox is null the value is 0, else the value will be 1.
'data-val' = the character position in the part number string.
Example: If the user types "07" into item# 2, then the script will need to filter the table where the part number has a "0" at character position 2 in the string, and "7" at character position 3 in the string
Most filters will search the ENTIRE string for a "07", but I need this to be specific to its position.
I also need it so that when the user also types in "L" into item#7 that the script will filter the part numbers where "07" are at char positions 2,3 AND where "L" is at char position 11 in the string.
Here's the main function I'm trying to deal with:
$('.modx').keyup(function() {
//I emtpy the "values" array and "position" array
arrval = [];
arrpos = [];
//Whatever textbox the user types in must indicate there is a value
$(this).attr('data-log', '1');
//I create an array of user input values and their positions
$('.modx').each(function() {
if ($(this).attr('data-log') == 1) {
arrval.push($(this).val());
arrpos.push($(this).attr('data-val'));
} else {}
});
/* THIS IS WHERE IM STUCK...Using the "values" array and "position" array,
check each part number where all values and positions are true.
I CANNOT COME UP WITH THE LOGIC HERE... */
});
I might be approaching this completely the wrong way. If so, I'd love to hear any other methods, or if you can think of the logic I could apply at the end of this keyup function that would be awesome too.
It is a regex bases solution
Add an additional data-* attribute data-length to the second and 5th modx text fields as shown below
<input type='text' data-log='0' data-val='1' tabindex='2' placeholder='03' class='size2 modx' id='item2' data-length="2"/>
....
<input type='text' data-log='0' data-val='7' tabindex='6' placeholder='53'class='size2 modx' id='item6' data-length="2"/>
then
var $modxs = $('.modx').keyup(function () {
var string = $modxs.map(function () {
var value = $.trim(this.value),
length = $(this).data('length') || 1;
while (value.length < length) {
value += '.';
}
return value;
}).get().join('');
string = string.replace(/(.{3})(.{5})(.{1})/, '$1-$2-$3');
var regex = new RegExp(string, 'i');
$('#partNumbers tbody tr').hide().filter(function () {
return regex.test($.trim($(this).children().first().text()))
}).show()
});
$('#clearBtn').click(function(){
$modxs.val('');
$('#partNumbers tbody tr').show()
})
Demo: Fiddle
First, let's see the logic. jQuery's filter() function, which seems to be the most practical to use here, works by running a filter function for every result element. When this function returns true, the element will be included in the filtered set.
So, in the filter function we need to check whether the value for the actual row (the text value of the first cell in the row in this case) satisfies all the requirements stored in your arrays.
For this, we iterate on arrpos. For every value we use substr() to extract the relevant part of the examined string (position is the current one from arrpos, length is the length of the current arrval element) and then compare it to the current value from arrval. If they are not equal, the check already failed, so we return false. If the for loop finishes running, we are certain we can return true (every check was successful).
A simple implementation (not thoroughly tested, just an illustration):
$('#partNumbers tbody tr') //get the rows
.hide() //hide all of them
.filter(function () {
var tValue = $(this).find('td:first').text();
for (var i = 0, l = arrpos.length; i < l; i++) {
if (tValue.substr(arrpos[i], arrval[i].length) !== arrval[i]) {
return false;
}
}
return true;
})
.show(); //show only the filtered ones (for which true was returned)
jsFiddle Demo

Including a for loop in an if statement

I'm building an application in which I want to display some errors when a user enters invalid values in an input box. A correct value is appended as 'entry' to a div if no errors were found. In total there are 3 cases when to display errors:
The input value is empty
The input value is a number
The input value already exists
These errors are displayed with if else statements.
1.and 2. were easy, but the problem case (3.) only validates against the first element of class .cat_entry.
if(cat_input == '') { // generate errors
errorDisplay(error_input_empty);
} else if(!isNaN(cat_input)) {
errorDisplay(error_input_number);
} else if($('.cat_entry') == cat_input) { // THIS IS THE PROBLEMATIC LINE
// .cat_entry is the class of the entries that have been appended
errorDisplay(error_duplicate);
} else {
// stuff
};
So I believe I need a for loop/ .each() (no problem so far), but how do I include this as a condition in an if statement? Something like.. if( for(i=0;i<$('.cat_entry').length;i++) { ... }; ... How to return true (or something similar) when one of the entries matches the input value, then pass the return value to the if statement?
EDIT: here is a jsFiddle with the relevant code. I updated it with $.inArray() method. I'd like to try and use this instead of a for / .each() loop.
You can try this:
var a=$('.cat_entry'),o={};
for(i=0;i<a.length;i++) {
var s=a[i].val();
if(s in o){
errorDisplay(error_duplicate);
return;
}
o[s]=true;
}
or
var o={};
$('.cat_entry').each(function(){
var s=$(this).val();
if(s in o){
errorDisplay(error_duplicate);
return;
}
o[s]=true;
}
You can actually use the jQuery inArray function for this, such as:
else if($.inArray(cat_input, $('.cat_entry') != -1)
}
The solution was to add this to the function:
var isDuplicate = false;
$('.cat_entry').each(function() {
if(!$(this).text().indexOf(cat_input)) {
isDuplicate = true;
}
// And in the if else loop:
else if(isDuplicate == true)
//and just before the function ends
isDuplicate = false;
Thanks to all for the help you offered.

Categories